diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2019-01-10 01:12:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-10 01:12:22 +0100 |
commit | a685c049c04036e12371a05702f5570d74340d55 (patch) | |
tree | a0b35f676645c254dba01a4642f6aca22e38122f | |
parent | d253a45e1c147f5174265d71d7419da7bd52a88b (diff) | |
parent | ef4d6abe7c7fab6cbff975b32e76b09feee56074 (diff) | |
download | systemd-a685c049c04036e12371a05702f5570d74340d55.tar.gz |
Merge pull request #11374 from keszybz/journal-fixes
Journal/journal-remote/coredump fixes
-rw-r--r-- | src/basic/io-util.c | 10 | ||||
-rw-r--r-- | src/basic/io-util.h | 2 | ||||
-rw-r--r-- | src/basic/process-util.c | 73 | ||||
-rw-r--r-- | src/coredump/coredump.c | 40 | ||||
-rw-r--r-- | src/journal-remote/journal-gatewayd.c | 53 | ||||
-rw-r--r-- | src/journal-remote/journal-remote-main.c | 39 | ||||
-rw-r--r-- | src/journal-remote/journal-remote.c | 3 | ||||
-rw-r--r-- | src/journal-remote/microhttpd-util.c | 11 | ||||
-rw-r--r-- | src/journal-remote/microhttpd-util.h | 1 | ||||
-rw-r--r-- | src/journal/journald-native.c | 74 | ||||
-rw-r--r-- | src/journal/journald-server.c | 29 | ||||
-rw-r--r-- | src/shared/journal-importer.c | 5 | ||||
-rw-r--r-- | src/shared/journal-importer.h | 3 |
13 files changed, 170 insertions, 173 deletions
diff --git a/src/basic/io-util.c b/src/basic/io-util.c index 1f64cc933b..575398fbe6 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -8,6 +8,7 @@ #include <unistd.h> #include "io-util.h" +#include "string-util.h" #include "time-util.h" int flush_fd(int fd) { @@ -252,3 +253,12 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) { return q - (const uint8_t*) p; } + +char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) { + char *x; + + x = strappend(field, value); + if (x) + iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x); + return x; +} diff --git a/src/basic/io-util.h b/src/basic/io-util.h index ed189b5820..792a64ad5e 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -71,3 +71,5 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) { #define IOVEC_MAKE(base, len) (struct iovec) IOVEC_INIT(base, len) #define IOVEC_INIT_STRING(string) IOVEC_INIT((char*) string, strlen(string)) #define IOVEC_MAKE_STRING(string) (struct iovec) IOVEC_INIT_STRING(string) + +char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value); diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 448503409b..31fdbd9346 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -129,6 +129,13 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + if (max_length == 0) { + /* This is supposed to be a safety guard against runaway command lines. */ + long l = sysconf(_SC_ARG_MAX); + assert(l > 0); + max_length = l; + } + if (max_length == 1) { /* If there's only room for one byte, return the empty string */ @@ -139,32 +146,6 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * *line = ans; return 0; - } else if (max_length == 0) { - size_t len = 0, allocated = 0; - - while ((c = getc(f)) != EOF) { - - if (!GREEDY_REALLOC(ans, allocated, len+3)) { - free(ans); - return -ENOMEM; - } - - if (isprint(c)) { - if (space) { - ans[len++] = ' '; - space = false; - } - - ans[len++] = c; - } else if (len > 0) - space = true; - } - - if (len > 0) - ans[len] = '\0'; - else - ans = mfree(ans); - } else { bool dotdotdot = false; size_t left; @@ -236,34 +217,30 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * if (h < 0) return h; - if (max_length == 0) - ans = strjoin("[", t, "]"); - else { - size_t l; + size_t l = strlen(t); - l = strlen(t); - - if (l + 3 <= max_length) - ans = strjoin("[", t, "]"); - else if (max_length <= 6) { + if (l + 3 <= max_length) { + ans = strjoin("[", t, "]"); + if (!ans) + return -ENOMEM; - ans = new(char, max_length); - if (!ans) - return -ENOMEM; + } else if (max_length <= 6) { + ans = new(char, max_length); + if (!ans) + return -ENOMEM; - memcpy(ans, "[...]", max_length-1); - ans[max_length-1] = 0; - } else { - t[max_length - 6] = 0; + memcpy(ans, "[...]", max_length-1); + ans[max_length-1] = 0; + } else { + t[max_length - 6] = 0; - /* Chop off final spaces */ - delete_trailing_chars(t, WHITESPACE); + /* Chop off final spaces */ + delete_trailing_chars(t, WHITESPACE); - ans = strjoin("[", t, "...]"); - } + ans = strjoin("[", t, "...]"); + if (!ans) + return -ENOMEM; } - if (!ans) - return -ENOMEM; } *line = ans; diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 0c888b26f9..516f63d3e0 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -794,15 +794,16 @@ log: core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], " (", context[CONTEXT_COMM], ") of user ", context[CONTEXT_UID], " dumped core.", - journald_crash ? "\nCoredump diverted to " : NULL, - journald_crash ? filename : NULL); + journald_crash && filename ? "\nCoredump diverted to " : NULL, + journald_crash && filename ? filename : NULL); if (!core_message) return log_oom(); if (journald_crash) { - /* We cannot log to the journal, so just print the MESSAGE. + /* We cannot log to the journal, so just print the message. * The target was set previously to something safe. */ - log_dispatch(LOG_ERR, 0, core_message); + assert(startswith(core_message, "MESSAGE=")); + log_dispatch(LOG_ERR, 0, core_message + strlen("MESSAGE=")); return 0; } @@ -1062,19 +1063,10 @@ static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd) return 0; } -static char* set_iovec_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) { - char *x; - - x = strappend(field, value); - if (x) - iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x); - return x; -} - static char* set_iovec_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) { char *x; - x = set_iovec_field(iovec, n_iovec, field, value); + x = set_iovec_string_field(iovec, n_iovec, field, value); free(value); return x; } @@ -1124,36 +1116,36 @@ static int gather_pid_metadata( disable_coredumps(); } - set_iovec_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]); + set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]); } if (cg_pid_get_user_unit(pid, &t) >= 0) set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t); /* The next few are mandatory */ - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM])) return log_oom(); if (context[CONTEXT_EXE] && - !set_iovec_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE])) + !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE])) return log_oom(); if (sd_pid_get_session(pid, &t) >= 0) @@ -1221,7 +1213,7 @@ static int gather_pid_metadata( iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t); if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo)) - set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo)); + set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo)); return 0; /* we successfully acquired all metadata */ } diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 4185af63e1..af45fa549a 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -461,7 +461,7 @@ static int request_handler_entries( struct MHD_Connection *connection, void *connection_cls) { - struct MHD_Response *response; + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; RequestMeta *m = connection_cls; int r; @@ -503,11 +503,7 @@ static int request_handler_entries( return respond_oom(connection); MHD_add_response_header(response, "Content-Type", mime_types[m->mode]); - - r = MHD_queue_response(connection, MHD_HTTP_OK, response); - MHD_destroy_response(response); - - return r; + return MHD_queue_response(connection, MHD_HTTP_OK, response); } static int output_field(FILE *f, OutputMode m, const char *d, size_t l) { @@ -619,7 +615,7 @@ static int request_handler_fields( const char *field, void *connection_cls) { - struct MHD_Response *response; + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; RequestMeta *m = connection_cls; int r; @@ -642,11 +638,7 @@ static int request_handler_fields( return respond_oom(connection); MHD_add_response_header(response, "Content-Type", mime_types[m->mode == OUTPUT_JSON ? OUTPUT_JSON : OUTPUT_SHORT]); - - r = MHD_queue_response(connection, MHD_HTTP_OK, response); - MHD_destroy_response(response); - - return r; + return MHD_queue_response(connection, MHD_HTTP_OK, response); } static int request_handler_redirect( @@ -654,8 +646,7 @@ static int request_handler_redirect( const char *target) { char *page; - struct MHD_Response *response; - int ret; + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; assert(connection); assert(target); @@ -671,11 +662,7 @@ static int request_handler_redirect( MHD_add_response_header(response, "Content-Type", "text/html"); MHD_add_response_header(response, "Location", target); - - ret = MHD_queue_response(connection, MHD_HTTP_MOVED_PERMANENTLY, response); - MHD_destroy_response(response); - - return ret; + return MHD_queue_response(connection, MHD_HTTP_MOVED_PERMANENTLY, response); } static int request_handler_file( @@ -683,8 +670,7 @@ static int request_handler_file( const char *path, const char *mime_type) { - struct MHD_Response *response; - int ret; + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; _cleanup_close_ int fd = -1; struct stat st; @@ -702,15 +688,10 @@ static int request_handler_file( response = MHD_create_response_from_fd_at_offset64(st.st_size, fd, 0); if (!response) return respond_oom(connection); - - fd = -1; + TAKE_FD(fd); MHD_add_response_header(response, "Content-Type", mime_type); - - ret = MHD_queue_response(connection, MHD_HTTP_OK, response); - MHD_destroy_response(response); - - return ret; + return MHD_queue_response(connection, MHD_HTTP_OK, response); } static int get_virtualization(char **v) { @@ -747,14 +728,13 @@ static int request_handler_machine( struct MHD_Connection *connection, void *connection_cls) { - struct MHD_Response *response; + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; RequestMeta *m = connection_cls; int r; _cleanup_free_ char* hostname = NULL, *os_name = NULL; uint64_t cutoff_from = 0, cutoff_to = 0, usage = 0; - char *json; sd_id128_t mid, bid; - _cleanup_free_ char *v = NULL; + _cleanup_free_ char *v = NULL, *json = NULL; assert(connection); assert(m); @@ -803,21 +783,16 @@ static int request_handler_machine( usage, cutoff_from, cutoff_to); - if (r < 0) return respond_oom(connection); response = MHD_create_response_from_buffer(strlen(json), json, MHD_RESPMEM_MUST_FREE); - if (!response) { - free(json); + if (!response) return respond_oom(connection); - } + TAKE_PTR(json); MHD_add_response_header(response, "Content-Type", "application/json"); - r = MHD_queue_response(connection, MHD_HTTP_OK, response); - MHD_destroy_response(response); - - return r; + return MHD_queue_response(connection, MHD_HTTP_OK, response); } static int request_handler( diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c index e1748cb46b..802c3ea608 100644 --- a/src/journal-remote/journal-remote-main.c +++ b/src/journal-remote/journal-remote-main.c @@ -221,16 +221,17 @@ static int process_http_upload( journal_remote_server_global->seal); if (r == -EAGAIN) break; - else if (r < 0) { - log_warning("Failed to process data for connection %p", connection); - if (r == -E2BIG) - return mhd_respondf(connection, - r, MHD_HTTP_PAYLOAD_TOO_LARGE, - "Entry is too large, maximum is " STRINGIFY(DATA_SIZE_MAX) " bytes."); + if (r < 0) { + if (r == -ENOBUFS) + log_warning_errno(r, "Entry is above the maximum of %u, aborting connection %p.", + DATA_SIZE_MAX, connection); + else if (r == -E2BIG) + log_warning_errno(r, "Entry with more fields than the maximum of %u, aborting connection %p.", + ENTRY_FIELD_COUNT_MAX, connection); else - return mhd_respondf(connection, - r, MHD_HTTP_UNPROCESSABLE_ENTITY, - "Processing failed: %m."); + log_warning_errno(r, "Failed to process data, aborting connection %p: %m", + connection); + return MHD_NO; } } @@ -264,6 +265,7 @@ static int request_handler( const char *header; int r, code, fd; _cleanup_free_ char *hostname = NULL; + size_t len; assert(connection); assert(connection_cls); @@ -283,12 +285,27 @@ static int request_handler( if (!streq(url, "/upload")) return mhd_respond(connection, MHD_HTTP_NOT_FOUND, "Not found."); - header = MHD_lookup_connection_value(connection, - MHD_HEADER_KIND, "Content-Type"); + header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Type"); if (!header || !streq(header, "application/vnd.fdo.journal")) return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE, "Content-Type: application/vnd.fdo.journal is required."); + header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Length"); + if (!header) + return mhd_respond(connection, MHD_HTTP_LENGTH_REQUIRED, + "Content-Length header is required."); + r = safe_atozu(header, &len); + if (r < 0) + return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED, + "Content-Length: %s cannot be parsed: %m", header); + + if (len > ENTRY_SIZE_MAX) + /* When serialized, an entry of maximum size might be slightly larger, + * so this does not correspond exactly to the limit in journald. Oh well. + */ + return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE, + "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX); + { const union MHD_ConnectionInfo *ci; diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index 3c0916c438..1da32c5f85 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -407,6 +407,9 @@ int journal_remote_handle_raw_source( log_debug("%zu active sources remaining", s->active); return 0; } else if (r == -E2BIG) { + log_notice("Entry with too many fields, skipped"); + return 1; + } else if (r == -ENOBUFS) { log_notice("Entry too big, skipped"); return 1; } else if (r == -EAGAIN) { diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c index adf40b5abd..6d049d11f7 100644 --- a/src/journal-remote/microhttpd-util.c +++ b/src/journal-remote/microhttpd-util.c @@ -32,21 +32,16 @@ static int mhd_respond_internal(struct MHD_Connection *connection, const char *buffer, size_t size, enum MHD_ResponseMemoryMode mode) { - struct MHD_Response *response; - int r; - assert(connection); - response = MHD_create_response_from_buffer(size, (char*) buffer, mode); + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response + = MHD_create_response_from_buffer(size, (char*) buffer, mode); if (!response) return MHD_NO; log_debug("Queueing response %u: %s", code, buffer); MHD_add_response_header(response, "Content-Type", "text/plain"); - r = MHD_queue_response(connection, code, response); - MHD_destroy_response(response); - - return r; + return MHD_queue_response(connection, code, response); } int mhd_respond(struct MHD_Connection *connection, diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h index 364cd0f7cf..ba51d847e4 100644 --- a/src/journal-remote/microhttpd-util.h +++ b/src/journal-remote/microhttpd-util.h @@ -75,3 +75,4 @@ int check_permissions(struct MHD_Connection *connection, int *code, char **hostn int setup_gnutls_logger(char **categories); DEFINE_TRIVIAL_CLEANUP_FUNC(struct MHD_Daemon*, MHD_stop_daemon); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct MHD_Response*, MHD_destroy_response); diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index e86178ed77..221188db16 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -110,7 +110,7 @@ static int server_process_entry( int priority = LOG_INFO; pid_t object_pid = 0; const char *p; - int r = 0; + int r = 1; p = buffer; @@ -122,8 +122,7 @@ static int server_process_entry( if (!e) { /* Trailing noise, let's ignore it, and flush what we collected */ log_debug("Received message with trailing noise, ignoring."); - r = 1; /* finish processing of the message */ - break; + break; /* finish processing of the message */ } if (e == p) { @@ -133,14 +132,17 @@ static int server_process_entry( } if (IN_SET(*p, '.', '#')) { - /* Ignore control commands for now, and - * comments too. */ + /* Ignore control commands for now, and comments too. */ *remaining -= (e - p) + 1; p = e + 1; continue; } /* A property follows */ + if (n > ENTRY_FIELD_COUNT_MAX) { + log_debug("Received an entry that has more than " STRINGIFY(ENTRY_FIELD_COUNT_MAX) " fields, ignoring entry."); + goto finish; + } /* n existing properties, 1 new, +1 for _TRANSPORT */ if (!GREEDY_REALLOC(iovec, m, @@ -148,7 +150,7 @@ static int server_process_entry( N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS + client_context_extra_fields_n_iovec(context))) { r = log_oom(); - break; + goto finish; } q = memchr(p, '=', e - p); @@ -157,6 +159,16 @@ static int server_process_entry( size_t l; l = e - p; + if (l > DATA_SIZE_MAX) { + log_debug("Received text block of %zu bytes is too large, ignoring entry.", l); + goto finish; + } + + if (entry_size + l + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */ + log_debug("Entry is too big (%zu bytes after processing %zu entries), ignoring entry.", + entry_size + l, n + 1); + goto finish; + } /* If the field name starts with an underscore, skip the variable, since that indicates * a trusted field */ @@ -174,7 +186,7 @@ static int server_process_entry( p = e + 1; continue; } else { - uint64_t l; + uint64_t l, total; char *k; if (*remaining < e - p + 1 + sizeof(uint64_t) + 1) { @@ -183,10 +195,16 @@ static int server_process_entry( } l = unaligned_read_le64(e + 1); - if (l > DATA_SIZE_MAX) { - log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l); - break; + log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring entry.", l); + goto finish; + } + + total = (e - p) + 1 + l; + if (entry_size + total + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */ + log_debug("Entry is too big (%"PRIu64"bytes after processing %zu fields), ignoring.", + entry_size + total, n + 1); + goto finish; } if ((uint64_t) *remaining < e - p + 1 + sizeof(uint64_t) + l + 1 || @@ -195,7 +213,7 @@ static int server_process_entry( break; } - k = malloc((e - p) + 1 + l); + k = malloc(total); if (!k) { log_oom(); break; @@ -223,15 +241,8 @@ static int server_process_entry( } } - if (n <= 0) { - r = 1; + if (n <= 0) goto finish; - } - - if (!client_context_test_priority(context, priority)) { - r = 0; - goto finish; - } tn = n++; iovec[tn] = IOVEC_MAKE_STRING("_TRANSPORT=journal"); @@ -242,6 +253,11 @@ static int server_process_entry( goto finish; } + r = 0; /* Success, we read the message. */ + + if (!client_context_test_priority(context, priority)) + goto finish; + if (message) { if (s->forward_to_syslog) server_forward_syslog(s, syslog_fixup_facility(priority), identifier, message, ucred, tv); @@ -313,15 +329,13 @@ void server_process_native_file( bool sealed; int r; - /* Data is in the passed fd, since it didn't fit in a - * datagram. */ + /* Data is in the passed fd, probably it didn't fit in a datagram. */ assert(s); assert(fd >= 0); /* If it's a memfd, check if it is sealed. If so, we can just - * use map it and use it, and do not need to copy the data - * out. */ + * mmap it and use it, and do not need to copy the data out. */ sealed = memfd_get_sealed(fd) > 0; if (!sealed && (!ucred || ucred->uid != 0)) { @@ -362,8 +376,10 @@ void server_process_native_file( if (st.st_size <= 0) return; - if (st.st_size > ENTRY_SIZE_MAX) { - log_error("File passed too large. Ignoring."); + /* When !sealed, set a lower memory limit. We have to read the file, + * effectively doubling memory use. */ + if (st.st_size > ENTRY_SIZE_MAX / (sealed ? 1 : 2)) { + log_error("File passed too large (%"PRIu64" bytes). Ignoring.", (uint64_t) st.st_size); return; } @@ -388,7 +404,7 @@ void server_process_native_file( ssize_t n; if (fstatvfs(fd, &vfs) < 0) { - log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m"); + log_error_errno(errno, "Failed to stat file system of passed file, not processing it: %m"); return; } @@ -398,7 +414,7 @@ void server_process_native_file( * https://github.com/systemd/systemd/issues/1822 */ if (vfs.f_flag & ST_MANDLOCK) { - log_error("Received file descriptor from file system with mandatory locking enabled, refusing."); + log_error("Received file descriptor from file system with mandatory locking enabled, not processing it."); return; } @@ -411,13 +427,13 @@ void server_process_native_file( * and so is SMB. */ r = fd_nonblock(fd, true); if (r < 0) { - log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m"); + log_error_errno(r, "Failed to make fd non-blocking, not processing it: %m"); return; } /* The file is not sealed, we can't map the file here, since * clients might then truncate it and trigger a SIGBUS for - * us. So let's stupidly read it */ + * us. So let's stupidly read it. */ p = malloc(st.st_size); if (!p) { diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 434325c179..2a960ebb3e 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -905,6 +905,7 @@ static void dispatch_message_real( pid_t object_pid) { char source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)]; + _cleanup_free_ char *cmdline1 = NULL, *cmdline2 = NULL; uid_t journal_uid; ClientContext *o; @@ -921,20 +922,23 @@ static void dispatch_message_real( IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->uid, uid_t, uid_is_valid, UID_FMT, "_UID"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->gid, gid_t, gid_is_valid, GID_FMT, "_GID"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->comm, "_COMM"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->exe, "_EXE"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->cmdline, "_CMDLINE"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->capeff, "_CAP_EFFECTIVE"); + IOVEC_ADD_STRING_FIELD(iovec, n, c->comm, "_COMM"); /* At most TASK_COMM_LENGTH (16 bytes) */ + IOVEC_ADD_STRING_FIELD(iovec, n, c->exe, "_EXE"); /* A path, so at most PATH_MAX (4096 bytes) */ - IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT"); + if (c->cmdline) + /* At most _SC_ARG_MAX (2MB usually), which is too much to put on stack. + * Let's use a heap allocation for this one. */ + cmdline1 = set_iovec_string_field(iovec, &n, "_CMDLINE=", c->cmdline); + IOVEC_ADD_STRING_FIELD(iovec, n, c->capeff, "_CAP_EFFECTIVE"); /* Read from /proc/.../status */ + IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "_AUDIT_SESSION"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->loginuid, uid_t, uid_is_valid, UID_FMT, "_AUDIT_LOGINUID"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->cgroup, "_SYSTEMD_CGROUP"); + IOVEC_ADD_STRING_FIELD(iovec, n, c->cgroup, "_SYSTEMD_CGROUP"); /* A path */ IOVEC_ADD_STRING_FIELD(iovec, n, c->session, "_SYSTEMD_SESSION"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->owner_uid, uid_t, uid_is_valid, UID_FMT, "_SYSTEMD_OWNER_UID"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->unit, "_SYSTEMD_UNIT"); + IOVEC_ADD_STRING_FIELD(iovec, n, c->unit, "_SYSTEMD_UNIT"); /* Unit names are bounded by UNIT_NAME_MAX */ IOVEC_ADD_STRING_FIELD(iovec, n, c->user_unit, "_SYSTEMD_USER_UNIT"); IOVEC_ADD_STRING_FIELD(iovec, n, c->slice, "_SYSTEMD_SLICE"); IOVEC_ADD_STRING_FIELD(iovec, n, c->user_slice, "_SYSTEMD_USER_SLICE"); @@ -955,13 +959,14 @@ static void dispatch_message_real( IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->uid, uid_t, uid_is_valid, UID_FMT, "OBJECT_UID"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->gid, gid_t, gid_is_valid, GID_FMT, "OBJECT_GID"); + /* See above for size limits, only ->cmdline may be large, so use a heap allocation for it. */ IOVEC_ADD_STRING_FIELD(iovec, n, o->comm, "OBJECT_COMM"); IOVEC_ADD_STRING_FIELD(iovec, n, o->exe, "OBJECT_EXE"); - IOVEC_ADD_STRING_FIELD(iovec, n, o->cmdline, "OBJECT_CMDLINE"); - IOVEC_ADD_STRING_FIELD(iovec, n, o->capeff, "OBJECT_CAP_EFFECTIVE"); + if (o->cmdline) + cmdline2 = set_iovec_string_field(iovec, &n, "OBJECT_CMDLINE=", o->cmdline); + IOVEC_ADD_STRING_FIELD(iovec, n, o->capeff, "OBJECT_CAP_EFFECTIVE"); IOVEC_ADD_SIZED_FIELD(iovec, n, o->label, o->label_size, "OBJECT_SELINUX_CONTEXT"); - IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "OBJECT_AUDIT_SESSION"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->loginuid, uid_t, uid_is_valid, UID_FMT, "OBJECT_AUDIT_LOGINUID"); @@ -1276,8 +1281,7 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void return log_error_errno(errno, "recvmsg() failed: %m"); } - CMSG_FOREACH(cmsg, &msghdr) { - + CMSG_FOREACH(cmsg, &msghdr) if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) @@ -1295,7 +1299,6 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void fds = (int*) CMSG_DATA(cmsg); n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); } - } /* And a trailing NUL, just in case */ s->buffer[n] = 0; diff --git a/src/shared/journal-importer.c b/src/shared/journal-importer.c index b0e619205d..8638cd3cc9 100644 --- a/src/shared/journal-importer.c +++ b/src/shared/journal-importer.c @@ -23,6 +23,9 @@ enum { }; static int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) { + if (iovw->count >= ENTRY_FIELD_COUNT_MAX) + return -E2BIG; + if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1)) return log_oom(); @@ -97,7 +100,7 @@ static int get_line(JournalImporter *imp, char **line, size_t *size) { imp->scanned = imp->filled; if (imp->scanned >= DATA_SIZE_MAX) - return log_error_errno(SYNTHETIC_ERRNO(E2BIG), + return log_error_errno(SYNTHETIC_ERRNO(ENOBUFS), "Entry is bigger than %u bytes.", DATA_SIZE_MAX); diff --git a/src/shared/journal-importer.h b/src/shared/journal-importer.h index 53354b7c78..7914c0cf5f 100644 --- a/src/shared/journal-importer.h +++ b/src/shared/journal-importer.h @@ -21,6 +21,9 @@ #endif #define LINE_CHUNK 8*1024u +/* The maximum number of fields in an entry */ +#define ENTRY_FIELD_COUNT_MAX 1024 + struct iovec_wrapper { struct iovec *iovec; size_t size_bytes; |