From 4cdb970b5bf21404c0fcac6bc825a4e6d433bf1c Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 18 Nov 2021 12:25:27 +0000 Subject: [PATCH 1/3] journal: Use consistent naming for iovec in audit logic Let's use iovec and n for the iovec variable and it's size just like we do in the rest of the journal code. --- src/journal/journald-audit.c | 90 ++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index 507b12137d..504a6ec726 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -15,14 +15,14 @@ typedef struct MapField { const char *audit_field; const char *journal_field; - int (*map)(const char *field, const char **p, struct iovec **iov, size_t *n_iov); + int (*map)(const char *field, const char **p, struct iovec **iovec, size_t *n); } MapField; static int map_simple_field( const char *field, const char **p, - struct iovec **iov, - size_t *n_iov) { + struct iovec **iovec, + size_t *n) { _cleanup_free_ char *c = NULL; size_t l = 0; @@ -30,8 +30,8 @@ static int map_simple_field( assert(field); assert(p); - assert(iov); - assert(n_iov); + assert(iovec); + assert(n); l = strlen(field); c = malloc(l + 1); @@ -48,10 +48,10 @@ static int map_simple_field( c[l] = 0; - if (!GREEDY_REALLOC(*iov, *n_iov + 1)) + if (!GREEDY_REALLOC(*iovec, *n + 1)) return -ENOMEM; - (*iov)[(*n_iov)++] = IOVEC_MAKE(c, l); + (*iovec)[(*n)++] = IOVEC_MAKE(c, l); *p = e; c = NULL; @@ -62,8 +62,8 @@ static int map_simple_field( static int map_string_field_internal( const char *field, const char **p, - struct iovec **iov, - size_t *n_iov, + struct iovec **iovec, + size_t *n, bool filter_printable) { _cleanup_free_ char *c = NULL; @@ -72,8 +72,8 @@ static int map_string_field_internal( assert(field); assert(p); - assert(iov); - assert(n_iov); + assert(iovec); + assert(n); /* The kernel formats string fields in one of two formats. */ @@ -128,10 +128,10 @@ static int map_string_field_internal( } else return 0; - if (!GREEDY_REALLOC(*iov, *n_iov + 1)) + if (!GREEDY_REALLOC(*iovec, *n + 1)) return -ENOMEM; - (*iov)[(*n_iov)++] = IOVEC_MAKE(c, l); + (*iovec)[(*n)++] = IOVEC_MAKE(c, l); *p = e; c = NULL; @@ -139,19 +139,19 @@ static int map_string_field_internal( return 1; } -static int map_string_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov) { - return map_string_field_internal(field, p, iov, n_iov, false); +static int map_string_field(const char *field, const char **p, struct iovec **iovec, size_t *n) { + return map_string_field_internal(field, p, iovec, n, false); } -static int map_string_field_printable(const char *field, const char **p, struct iovec **iov, size_t *n_iov) { - return map_string_field_internal(field, p, iov, n_iov, true); +static int map_string_field_printable(const char *field, const char **p, struct iovec **iovec, size_t *n) { + return map_string_field_internal(field, p, iovec, n, true); } static int map_generic_field( const char *prefix, const char **p, - struct iovec **iov, - size_t *n_iov) { + struct iovec **iovec, + size_t *n) { const char *e, *f; char *c, *t; @@ -196,7 +196,7 @@ static int map_generic_field( e++; - r = map_simple_field(c, &e, iov, n_iov); + r = map_simple_field(c, &e, iovec, n); if (r < 0) return r; @@ -255,14 +255,14 @@ static int map_all_fields( const MapField map_fields[], const char *prefix, bool handle_msg, - struct iovec **iov, - size_t *n_iov) { + struct iovec **iovec, + size_t *n) { int r; assert(p); - assert(iov); - assert(n_iov); + assert(iovec); + assert(n); for (;;) { bool mapped = false; @@ -296,7 +296,7 @@ static int map_all_fields( if (!c) return -ENOMEM; - return map_all_fields(c, map_fields_userspace, "AUDIT_FIELD_", false, iov, n_iov); + return map_all_fields(c, map_fields_userspace, "AUDIT_FIELD_", false, iovec, n); } } @@ -306,7 +306,7 @@ static int map_all_fields( if (!v) continue; - r = m->map(m->journal_field, &v, iov, n_iov); + r = m->map(m->journal_field, &v, iovec, n); if (r < 0) return log_debug_errno(r, "Failed to parse audit array: %m"); @@ -318,7 +318,7 @@ static int map_all_fields( } if (!mapped) { - r = map_generic_field(prefix, &p, iov, n_iov); + r = map_generic_field(prefix, &p, iovec, n); if (r < 0) return log_debug_errno(r, "Failed to parse audit array: %m"); @@ -330,8 +330,8 @@ static int map_all_fields( } void process_audit_string(Server *s, int type, const char *data, size_t size) { - size_t n_iov = 0, z; - _cleanup_free_ struct iovec *iov = NULL; + size_t n = 0, z; + _cleanup_free_ struct iovec *iovec = NULL; uint64_t seconds, msec, id; const char *p, *type_name; char id_field[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)], @@ -371,53 +371,53 @@ void process_audit_string(Server *s, int type, const char *data, size_t size) { if (isempty(p)) return; - iov = new(struct iovec, N_IOVEC_META_FIELDS + 8); - if (!iov) { + iovec = new(struct iovec, N_IOVEC_META_FIELDS + 8); + if (!iovec) { log_oom(); return; } - iov[n_iov++] = IOVEC_MAKE_STRING("_TRANSPORT=audit"); + iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=audit"); sprintf(source_time_field, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64, (usec_t) seconds * USEC_PER_SEC + (usec_t) msec * USEC_PER_MSEC); - iov[n_iov++] = IOVEC_MAKE_STRING(source_time_field); + iovec[n++] = IOVEC_MAKE_STRING(source_time_field); sprintf(type_field, "_AUDIT_TYPE=%i", type); - iov[n_iov++] = IOVEC_MAKE_STRING(type_field); + iovec[n++] = IOVEC_MAKE_STRING(type_field); sprintf(id_field, "_AUDIT_ID=%" PRIu64, id); - iov[n_iov++] = IOVEC_MAKE_STRING(id_field); + iovec[n++] = IOVEC_MAKE_STRING(id_field); assert_cc(4 == LOG_FAC(LOG_AUTH)); - iov[n_iov++] = IOVEC_MAKE_STRING("SYSLOG_FACILITY=4"); - iov[n_iov++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=audit"); + iovec[n++] = IOVEC_MAKE_STRING("SYSLOG_FACILITY=4"); + iovec[n++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=audit"); type_name = audit_type_name_alloca(type); type_field_name = strjoina("_AUDIT_TYPE_NAME=", type_name); - iov[n_iov++] = IOVEC_MAKE_STRING(type_field_name); + iovec[n++] = IOVEC_MAKE_STRING(type_field_name); m = strjoina("MESSAGE=", type_name, " ", p); - iov[n_iov++] = IOVEC_MAKE_STRING(m); + iovec[n++] = IOVEC_MAKE_STRING(m); - z = n_iov; + z = n; - map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, &iov, &n_iov); + map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, &iovec, &n); - if (!GREEDY_REALLOC(iov, n_iov + N_IOVEC_META_FIELDS)) { + if (!GREEDY_REALLOC(iovec, n + N_IOVEC_META_FIELDS)) { log_oom(); goto finish; } - server_dispatch_message(s, iov, n_iov, MALLOC_ELEMENTSOF(iov), NULL, NULL, LOG_NOTICE, 0); + server_dispatch_message(s, iovec, n, MALLOC_ELEMENTSOF(iovec), NULL, NULL, LOG_NOTICE, 0); finish: /* free() all entries that map_all_fields() added. All others * are allocated on the stack or are constant. */ - for (; z < n_iov; z++) - free(iov[z].iov_base); + for (; z < n; z++) + free(iovec[z].iov_base); } void server_process_audit_message( From ceb4192df6e38538e94e45e84a2d37f6187d7d27 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 18 Nov 2021 12:28:07 +0000 Subject: [PATCH 2/3] journal: Use mf as variable name for MapField So we can have a variable m for the max iovec size in the next commit like we do in the rest of the journal logic. --- src/journal/journald-audit.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index 504a6ec726..e31e5453b8 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -266,7 +266,7 @@ static int map_all_fields( for (;;) { bool mapped = false; - const MapField *m; + const MapField *mf; const char *v; p += strspn(p, WHITESPACE); @@ -301,12 +301,12 @@ static int map_all_fields( } /* Try to map the kernel fields to our own names */ - for (m = map_fields; m->audit_field; m++) { - v = startswith(p, m->audit_field); + for (mf = map_fields; mf->audit_field; mf++) { + v = startswith(p, mf->audit_field); if (!v) continue; - r = m->map(m->journal_field, &v, iovec, n); + r = mf->map(mf->journal_field, &v, iovec, n); if (r < 0) return log_debug_errno(r, "Failed to parse audit array: %m"); From 66e2bb282b44fceec0a495ff94208761fb2b7ceb Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 18 Nov 2021 12:37:04 +0000 Subject: [PATCH 3/3] journal: Limit the number of audit fields per log message Similar to the kmsg handler, let's also limit the number of fields we parse from audit messages. Fixes #19799 --- src/journal/journald-audit.c | 54 ++++++++++++++--------------------- src/journal/journald-server.h | 3 ++ 2 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index e31e5453b8..a8e3b175ac 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -15,13 +15,13 @@ typedef struct MapField { const char *audit_field; const char *journal_field; - int (*map)(const char *field, const char **p, struct iovec **iovec, size_t *n); + int (*map)(const char *field, const char **p, struct iovec *iovec, size_t *n); } MapField; static int map_simple_field( const char *field, const char **p, - struct iovec **iovec, + struct iovec *iovec, size_t *n) { _cleanup_free_ char *c = NULL; @@ -48,10 +48,7 @@ static int map_simple_field( c[l] = 0; - if (!GREEDY_REALLOC(*iovec, *n + 1)) - return -ENOMEM; - - (*iovec)[(*n)++] = IOVEC_MAKE(c, l); + iovec[(*n)++] = IOVEC_MAKE(c, l); *p = e; c = NULL; @@ -62,7 +59,7 @@ static int map_simple_field( static int map_string_field_internal( const char *field, const char **p, - struct iovec **iovec, + struct iovec *iovec, size_t *n, bool filter_printable) { @@ -128,10 +125,7 @@ static int map_string_field_internal( } else return 0; - if (!GREEDY_REALLOC(*iovec, *n + 1)) - return -ENOMEM; - - (*iovec)[(*n)++] = IOVEC_MAKE(c, l); + iovec[(*n)++] = IOVEC_MAKE(c, l); *p = e; c = NULL; @@ -139,18 +133,18 @@ static int map_string_field_internal( return 1; } -static int map_string_field(const char *field, const char **p, struct iovec **iovec, size_t *n) { +static int map_string_field(const char *field, const char **p, struct iovec *iovec, size_t *n) { return map_string_field_internal(field, p, iovec, n, false); } -static int map_string_field_printable(const char *field, const char **p, struct iovec **iovec, size_t *n) { +static int map_string_field_printable(const char *field, const char **p, struct iovec *iovec, size_t *n) { return map_string_field_internal(field, p, iovec, n, true); } static int map_generic_field( const char *prefix, const char **p, - struct iovec **iovec, + struct iovec *iovec, size_t *n) { const char *e, *f; @@ -255,8 +249,9 @@ static int map_all_fields( const MapField map_fields[], const char *prefix, bool handle_msg, - struct iovec **iovec, - size_t *n) { + struct iovec *iovec, + size_t *n, + size_t m) { int r; @@ -269,6 +264,13 @@ static int map_all_fields( const MapField *mf; const char *v; + if (*n >= m) { + log_debug( + "More fields in audit message than audit field limit (%i), skipping remaining fields", + N_IOVEC_AUDIT_FIELDS); + return 0; + } + p += strspn(p, WHITESPACE); if (*p == 0) @@ -296,7 +298,7 @@ static int map_all_fields( if (!c) return -ENOMEM; - return map_all_fields(c, map_fields_userspace, "AUDIT_FIELD_", false, iovec, n); + return map_all_fields(c, map_fields_userspace, "AUDIT_FIELD_", false, iovec, n, m); } } @@ -331,12 +333,12 @@ static int map_all_fields( void process_audit_string(Server *s, int type, const char *data, size_t size) { size_t n = 0, z; - _cleanup_free_ struct iovec *iovec = NULL; uint64_t seconds, msec, id; const char *p, *type_name; char id_field[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)], type_field[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)], source_time_field[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)]; + struct iovec iovec[N_IOVEC_META_FIELDS + 8 + N_IOVEC_AUDIT_FIELDS]; char *m, *type_field_name; int k; @@ -371,12 +373,6 @@ void process_audit_string(Server *s, int type, const char *data, size_t size) { if (isempty(p)) return; - iovec = new(struct iovec, N_IOVEC_META_FIELDS + 8); - if (!iovec) { - log_oom(); - return; - } - iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=audit"); sprintf(source_time_field, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64, @@ -403,16 +399,10 @@ void process_audit_string(Server *s, int type, const char *data, size_t size) { z = n; - map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, &iovec, &n); + map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, iovec, &n, ELEMENTSOF(iovec)); - if (!GREEDY_REALLOC(iovec, n + N_IOVEC_META_FIELDS)) { - log_oom(); - goto finish; - } + server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, LOG_NOTICE, 0); - server_dispatch_message(s, iovec, n, MALLOC_ELEMENTSOF(iovec), NULL, NULL, LOG_NOTICE, 0); - -finish: /* free() all entries that map_all_fields() added. All others * are allocated on the stack or are constant. */ diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index 53e75ff3b0..87d39de3ae 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -191,6 +191,9 @@ struct Server { /* kmsg: Maximum number of extra fields we'll import from udev's devices */ #define N_IOVEC_UDEV_FIELDS 32 +/* audit: Maximum number of extra fields we'll import from audit messages */ +#define N_IOVEC_AUDIT_FIELDS 64 + void server_dispatch_message(Server *s, struct iovec *iovec, size_t n, size_t m, ClientContext *c, const struct timeval *tv, int priority, pid_t object_pid); void server_driver_message(Server *s, pid_t object_pid, const char *message_id, const char *format, ...) _sentinel_ _printf_(4,0);