From e256e03710abfd96e74d0b278c2b7186e3c8888b Mon Sep 17 00:00:00 2001 From: David Tardon Date: Thu, 12 Jan 2023 15:47:09 +0100 Subject: [PATCH] coredump: put context array into a struct [dtardon: This is based on commit f46c706bdd4316ae8ed6baf7a8c382b90b84f648 , but does just the minimal change to introduce the Context struct that is needed by the following commit.] Related: #2155519 --- src/coredump/coredump.c | 208 +++++++++++++++++++++------------------- 1 file changed, 108 insertions(+), 100 deletions(-) diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index fb3a6ecfe9..ebc56d8342 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -91,6 +91,10 @@ enum { _CONTEXT_MAX }; +typedef struct Context { + const char *meta[_CONTEXT_MAX]; +} Context; + typedef enum CoredumpStorage { COREDUMP_STORAGE_NONE, COREDUMP_STORAGE_EXTERNAL, @@ -184,7 +188,7 @@ static int fix_acl(int fd, uid_t uid) { return 0; } -static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) { +static int fix_xattr(int fd, const Context *context) { static const char * const xattrs[_CONTEXT_MAX] = { [CONTEXT_PID] = "user.coredump.pid", @@ -209,10 +213,10 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) { for (i = 0; i < _CONTEXT_MAX; i++) { int k; - if (isempty(context[i]) || !xattrs[i]) + if (isempty(context->meta[i]) || !xattrs[i]) continue; - k = fsetxattr(fd, xattrs[i], context[i], strlen(context[i]), XATTR_CREATE); + k = fsetxattr(fd, xattrs[i], context->meta[i], strlen(context->meta[i]), XATTR_CREATE); if (k < 0 && r == 0) r = -errno; } @@ -230,7 +234,7 @@ static int fix_permissions( int fd, const char *filename, const char *target, - const char *context[_CONTEXT_MAX], + const Context *context, uid_t uid) { int r; @@ -273,18 +277,18 @@ static int maybe_remove_external_coredump(const char *filename, uint64_t size) { return 1; } -static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { +static int make_filename(const Context *context, char **ret) { _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL; sd_id128_t boot = {}; int r; assert(context); - c = filename_escape(context[CONTEXT_COMM]); + c = filename_escape(context->meta[CONTEXT_COMM]); if (!c) return -ENOMEM; - u = filename_escape(context[CONTEXT_UID]); + u = filename_escape(context->meta[CONTEXT_UID]); if (!u) return -ENOMEM; @@ -292,11 +296,11 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { if (r < 0) return r; - p = filename_escape(context[CONTEXT_PID]); + p = filename_escape(context->meta[CONTEXT_PID]); if (!p) return -ENOMEM; - t = filename_escape(context[CONTEXT_TIMESTAMP]); + t = filename_escape(context->meta[CONTEXT_TIMESTAMP]); if (!t) return -ENOMEM; @@ -313,7 +317,7 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { } static int save_external_coredump( - const char *context[_CONTEXT_MAX], + const Context *context, int input_fd, char **ret_filename, int *ret_node_fd, @@ -334,19 +338,19 @@ static int save_external_coredump( assert(ret_data_fd); assert(ret_size); - r = parse_uid(context[CONTEXT_UID], &uid); + r = parse_uid(context->meta[CONTEXT_UID], &uid); if (r < 0) return log_error_errno(r, "Failed to parse UID: %m"); - r = safe_atou64(context[CONTEXT_RLIMIT], &rlimit); + r = safe_atou64(context->meta[CONTEXT_RLIMIT], &rlimit); if (r < 0) - return log_error_errno(r, "Failed to parse resource limit: %s", context[CONTEXT_RLIMIT]); + return log_error_errno(r, "Failed to parse resource limit: %s", context->meta[CONTEXT_RLIMIT]); if (rlimit < page_size()) { /* Is coredumping disabled? Then don't bother saving/processing the coredump. * Anything below PAGE_SIZE cannot give a readable coredump (the kernel uses * ELF_EXEC_PAGESIZE which is not easily accessible, but is usually the same as PAGE_SIZE. */ log_info("Resource limits disable core dumping for process %s (%s).", - context[CONTEXT_PID], context[CONTEXT_COMM]); + context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]); return -EBADSLT; } @@ -371,7 +375,7 @@ static int save_external_coredump( r = copy_bytes(input_fd, fd, max_size, 0); if (r < 0) { - log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]); + log_error_errno(r, "Cannot store coredump of %s (%s): %m", context->meta[CONTEXT_PID], context->meta[CONTEXT_COMM]); goto fail; } *ret_truncated = r == 1; @@ -659,12 +663,12 @@ static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) { return 1; } -static int change_uid_gid(const char *context[]) { +static int change_uid_gid(const Context *context) { uid_t uid; gid_t gid; int r; - r = parse_uid(context[CONTEXT_UID], &uid); + r = parse_uid(context->meta[CONTEXT_UID], &uid); if (r < 0) return r; @@ -677,7 +681,7 @@ static int change_uid_gid(const char *context[]) { uid = gid = 0; } } else { - r = parse_gid(context[CONTEXT_GID], &gid); + r = parse_gid(context->meta[CONTEXT_GID], &gid); if (r < 0) return r; } @@ -685,23 +689,23 @@ static int change_uid_gid(const char *context[]) { return drop_privileges(uid, gid, 0); } -static bool is_journald_crash(const char *context[_CONTEXT_MAX]) { +static bool is_journald_crash(const Context *context) { assert(context); - return streq_ptr(context[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE); + return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_JOURNALD_SERVICE); } -static bool is_pid1_crash(const char *context[_CONTEXT_MAX]) { +static bool is_pid1_crash(const Context *context) { assert(context); - return streq_ptr(context[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) || - streq_ptr(context[CONTEXT_PID], "1"); + return streq_ptr(context->meta[CONTEXT_UNIT], SPECIAL_INIT_SCOPE) || + streq_ptr(context->meta[CONTEXT_PID], "1"); } #define SUBMIT_COREDUMP_FIELDS 4 static int submit_coredump( - const char *context[_CONTEXT_MAX], + Context *context, struct iovec *iovec, size_t n_iovec_allocated, size_t n_iovec, @@ -760,11 +764,11 @@ static int submit_coredump( if (coredump_size <= arg_process_size_max) { _cleanup_free_ char *stacktrace = NULL; - r = coredump_make_stack_trace(coredump_fd, context[CONTEXT_EXE], &stacktrace); + r = coredump_make_stack_trace(coredump_fd, context->meta[CONTEXT_EXE], &stacktrace); if (r >= 0) - core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], - " (", context[CONTEXT_COMM], ") of user ", - context[CONTEXT_UID], " dumped core.", + core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID], + " (", context->meta[CONTEXT_COMM], ") of user ", + context->meta[CONTEXT_UID], " dumped core.", journald_crash ? "\nCoredump diverted to " : "", journald_crash ? filename : "", "\n\n", stacktrace); @@ -779,9 +783,9 @@ static int submit_coredump( if (!core_message) #endif log: - core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], - " (", context[CONTEXT_COMM], ") of user ", - context[CONTEXT_UID], " dumped core.", + core_message = strjoin("MESSAGE=Process ", context->meta[CONTEXT_PID], + " (", context->meta[CONTEXT_COMM], ") of user ", + context->meta[CONTEXT_UID], " dumped core.", journald_crash && filename ? "\nCoredump diverted to " : NULL, journald_crash && filename ? filename : NULL); if (!core_message) @@ -826,7 +830,7 @@ log: return 0; } -static void map_context_fields(const struct iovec *iovec, const char* context[]) { +static void map_context_fields(const struct iovec *iovec, Context *context) { static const char * const context_field_names[] = { [CONTEXT_PID] = "COREDUMP_PID=", @@ -857,7 +861,7 @@ static void map_context_fields(const struct iovec *iovec, const char* context[]) /* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the * buffer, though not included in the iov_len count. (see below) */ - context[i] = p; + context->meta[i] = p; break; } } @@ -866,7 +870,7 @@ static int process_socket(int fd) { _cleanup_close_ int coredump_fd = -1; struct iovec *iovec = NULL; size_t n_iovec = 0, n_allocated = 0, i, k; - const char *context[_CONTEXT_MAX] = {}; + Context context = {}; int r; assert(fd >= 0); @@ -950,7 +954,7 @@ static int process_socket(int fd) { iovec[n_iovec].iov_len = (size_t) n; cmsg_close_all(&mh); - map_context_fields(iovec + n_iovec, context); + map_context_fields(iovec + n_iovec, &context); n_iovec++; } @@ -960,24 +964,24 @@ static int process_socket(int fd) { } /* Make sure we got all data we really need */ - assert(context[CONTEXT_PID]); - assert(context[CONTEXT_UID]); - assert(context[CONTEXT_GID]); - assert(context[CONTEXT_SIGNAL]); - assert(context[CONTEXT_TIMESTAMP]); - assert(context[CONTEXT_RLIMIT]); - assert(context[CONTEXT_HOSTNAME]); - assert(context[CONTEXT_COMM]); + assert(context.meta[CONTEXT_PID]); + assert(context.meta[CONTEXT_UID]); + assert(context.meta[CONTEXT_GID]); + assert(context.meta[CONTEXT_SIGNAL]); + assert(context.meta[CONTEXT_TIMESTAMP]); + assert(context.meta[CONTEXT_RLIMIT]); + assert(context.meta[CONTEXT_HOSTNAME]); + assert(context.meta[CONTEXT_COMM]); assert(coredump_fd >= 0); /* Small quirk: the journal fields contain the timestamp padded with six zeroes, so that the kernel-supplied 1s * granularity timestamps becomes 1µs granularity, i.e. the granularity systemd usually operates in. Since we * are reconstructing the original kernel context, we chop this off again, here. */ - k = strlen(context[CONTEXT_TIMESTAMP]); + k = strlen(context.meta[CONTEXT_TIMESTAMP]); if (k > 6) - context[CONTEXT_TIMESTAMP] = strndupa(context[CONTEXT_TIMESTAMP], k - 6); + context.meta[CONTEXT_TIMESTAMP] = strndupa(context.meta[CONTEXT_TIMESTAMP], k - 6); - r = submit_coredump(context, iovec, n_allocated, n_iovec, coredump_fd); + r = submit_coredump(&context, iovec, n_allocated, n_iovec, coredump_fd); finish: for (i = 0; i < n_iovec; i++) @@ -1062,7 +1066,7 @@ static char* set_iovec_field_free(struct iovec *iovec, size_t *n_iovec, const ch } static int gather_pid_metadata( - char* context[_CONTEXT_MAX], + Context *context, char **comm_fallback, struct iovec *iovec, size_t *n_iovec) { @@ -1077,65 +1081,69 @@ static int gather_pid_metadata( const char *p; int r, signo; - r = parse_pid(context[CONTEXT_PID], &pid); + r = parse_pid(context->meta[CONTEXT_PID], &pid); if (r < 0) - return log_error_errno(r, "Failed to parse PID \"%s\": %m", context[CONTEXT_PID]); + return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[CONTEXT_PID]); - r = get_process_comm(pid, &context[CONTEXT_COMM]); + r = get_process_comm(pid, &t); if (r < 0) { log_warning_errno(r, "Failed to get COMM, falling back to the command line: %m"); - context[CONTEXT_COMM] = strv_join(comm_fallback, " "); - if (!context[CONTEXT_COMM]) + context->meta[CONTEXT_COMM] = strv_join(comm_fallback, " "); + if (!context->meta[CONTEXT_COMM]) return log_oom(); - } + } else + context->meta[CONTEXT_COMM] = t; - r = get_process_exe(pid, &context[CONTEXT_EXE]); + r = get_process_exe(pid, &t); if (r < 0) log_warning_errno(r, "Failed to get EXE, ignoring: %m"); + else + context->meta[CONTEXT_EXE] = t; - if (cg_pid_get_unit(pid, &context[CONTEXT_UNIT]) >= 0) { - if (!is_journald_crash((const char**) context)) { + if (cg_pid_get_unit(pid, &t) >= 0) { + if (!is_journald_crash(context)) { /* OK, now we know it's not the journal, hence we can make use of it now. */ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); } /* If this is PID 1 disable coredump collection, we'll unlikely be able to process it later on. */ - if (is_pid1_crash((const char**) context)) { + if (is_pid1_crash(context)) { log_notice("Due to PID 1 having crashed coredump collection will now be turned off."); disable_coredumps(); } - set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]); - } + set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context->meta[CONTEXT_UNIT]); + } else + context->meta[CONTEXT_UNIT] = t; 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_string_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context->meta[CONTEXT_PID])) return log_oom(); - if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context->meta[CONTEXT_UID])) return log_oom(); - if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context->meta[CONTEXT_GID])) return log_oom(); - if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context->meta[CONTEXT_SIGNAL])) return log_oom(); - if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context->meta[CONTEXT_RLIMIT])) return log_oom(); - if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context->meta[CONTEXT_HOSTNAME])) return log_oom(); - if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context->meta[CONTEXT_COMM])) return log_oom(); - if (context[CONTEXT_EXE] && - !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE])) + if (context->meta[CONTEXT_EXE] && + !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context->meta[CONTEXT_EXE])) return log_oom(); if (sd_pid_get_session(pid, &t) >= 0) @@ -1198,11 +1206,11 @@ static int gather_pid_metadata( if (get_process_environ(pid, &t) >= 0) set_iovec_field_free(iovec, n_iovec, "COREDUMP_ENVIRON=", t); - t = strjoin("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000"); + t = strjoin("COREDUMP_TIMESTAMP=", context->meta[CONTEXT_TIMESTAMP], "000000"); if (t) iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t); - if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo)) + if (safe_atoi(context->meta[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo)) set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo)); return 0; /* we successfully acquired all metadata */ @@ -1210,7 +1218,7 @@ static int gather_pid_metadata( static int process_kernel(int argc, char* argv[]) { - char* context[_CONTEXT_MAX] = {}; + Context context = {}; struct iovec iovec[29 + SUBMIT_COREDUMP_FIELDS]; size_t i, n_iovec, n_to_free = 0; int r; @@ -1222,15 +1230,15 @@ static int process_kernel(int argc, char* argv[]) { return -EINVAL; } - context[CONTEXT_PID] = argv[1 + CONTEXT_PID]; - context[CONTEXT_UID] = argv[1 + CONTEXT_UID]; - context[CONTEXT_GID] = argv[1 + CONTEXT_GID]; - context[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL]; - context[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP]; - context[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT]; - context[CONTEXT_HOSTNAME] = argv[1 + CONTEXT_HOSTNAME]; + context.meta[CONTEXT_PID] = argv[1 + CONTEXT_PID]; + context.meta[CONTEXT_UID] = argv[1 + CONTEXT_UID]; + context.meta[CONTEXT_GID] = argv[1 + CONTEXT_GID]; + context.meta[CONTEXT_SIGNAL] = argv[1 + CONTEXT_SIGNAL]; + context.meta[CONTEXT_TIMESTAMP] = argv[1 + CONTEXT_TIMESTAMP]; + context.meta[CONTEXT_RLIMIT] = argv[1 + CONTEXT_RLIMIT]; + context.meta[CONTEXT_HOSTNAME] = argv[1 + CONTEXT_HOSTNAME]; - r = gather_pid_metadata(context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free); + r = gather_pid_metadata(&context, argv + 1 + CONTEXT_COMM, iovec, &n_to_free); if (r < 0) goto finish; @@ -1243,8 +1251,8 @@ static int process_kernel(int argc, char* argv[]) { assert(n_iovec <= ELEMENTSOF(iovec)); - if (is_journald_crash((const char**) context) || is_pid1_crash((const char**) context)) - r = submit_coredump((const char**) context, + if (is_journald_crash(&context) || is_pid1_crash(&context)) + r = submit_coredump(&context, iovec, ELEMENTSOF(iovec), n_iovec, STDIN_FILENO); else @@ -1255,15 +1263,15 @@ static int process_kernel(int argc, char* argv[]) { free(iovec[i].iov_base); /* Those fields are allocated by gather_pid_metadata */ - free(context[CONTEXT_COMM]); - free(context[CONTEXT_EXE]); - free(context[CONTEXT_UNIT]); + free((char *) context.meta[CONTEXT_COMM]); + free((char *) context.meta[CONTEXT_EXE]); + free((char *) context.meta[CONTEXT_UNIT]); return r; } static int process_backtrace(int argc, char *argv[]) { - char *context[_CONTEXT_MAX] = {}; + Context context = {}; _cleanup_free_ char *message = NULL; _cleanup_free_ struct iovec *iovec = NULL; size_t n_iovec, n_allocated, n_to_free = 0, i; @@ -1279,13 +1287,13 @@ static int process_backtrace(int argc, char *argv[]) { return -EINVAL; } - context[CONTEXT_PID] = argv[2 + CONTEXT_PID]; - context[CONTEXT_UID] = argv[2 + CONTEXT_UID]; - context[CONTEXT_GID] = argv[2 + CONTEXT_GID]; - context[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL]; - context[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP]; - context[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT]; - context[CONTEXT_HOSTNAME] = argv[2 + CONTEXT_HOSTNAME]; + context.meta[CONTEXT_PID] = argv[2 + CONTEXT_PID]; + context.meta[CONTEXT_UID] = argv[2 + CONTEXT_UID]; + context.meta[CONTEXT_GID] = argv[2 + CONTEXT_GID]; + context.meta[CONTEXT_SIGNAL] = argv[2 + CONTEXT_SIGNAL]; + context.meta[CONTEXT_TIMESTAMP] = argv[2 + CONTEXT_TIMESTAMP]; + context.meta[CONTEXT_RLIMIT] = argv[2 + CONTEXT_RLIMIT]; + context.meta[CONTEXT_HOSTNAME] = argv[2 + CONTEXT_HOSTNAME]; n_allocated = 34 + COREDUMP_STORAGE_EXTERNAL; /* 26 metadata, 2 static, +unknown input, 4 storage, rounded up */ @@ -1293,7 +1301,7 @@ static int process_backtrace(int argc, char *argv[]) { if (!iovec) return log_oom(); - r = gather_pid_metadata(context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free); + r = gather_pid_metadata(&context, argv + 2 + CONTEXT_COMM, iovec, &n_to_free); if (r < 0) goto finish; if (r > 0) { @@ -1320,10 +1328,10 @@ static int process_backtrace(int argc, char *argv[]) { if (journal_importer_eof(&importer)) { log_warning("Did not receive a full journal entry on stdin, ignoring message sent by reporter"); - message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], - " (", context[CONTEXT_COMM], ")" - " of user ", context[CONTEXT_UID], - " failed with ", context[CONTEXT_SIGNAL]); + message = strjoin("MESSAGE=Process ", context.meta[CONTEXT_PID], + " (", context.meta[CONTEXT_COMM], ")" + " of user ", context.meta[CONTEXT_UID], + " failed with ", context.meta[CONTEXT_SIGNAL]); if (!message) { r = log_oom(); goto finish; @@ -1349,9 +1357,9 @@ static int process_backtrace(int argc, char *argv[]) { free(iovec[i].iov_base); /* Those fields are allocated by gather_pid_metadata */ - free(context[CONTEXT_COMM]); - free(context[CONTEXT_EXE]); - free(context[CONTEXT_UNIT]); + free((char *) context.meta[CONTEXT_COMM]); + free((char *) context.meta[CONTEXT_EXE]); + free((char *) context.meta[CONTEXT_UNIT]); return r; }