]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
coredump: do not crash if we failed to acquire exe path
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 3 Jan 2022 08:24:03 +0000 (09:24 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Mon, 3 Jan 2022 22:44:44 +0000 (22:44 +0000)
The COREDUMP_EXE attribute is "optional", i.e. we continue to process the
crash even if we didn't acquire it. The coredump generation code assumed
that it is always available:

 #5 endswith at ../src/fundamental/string-util-fundamental.c:41
 [ endswith() is called with NULL here, and an assertion fails. ]
 #6 submit_coredump at ../src/coredump/coredump.c:823
 #7 process_socket at ../src/coredump/coredump.c:1038
 #8 run at ../src/coredump/coredump.c:1413

We use the exe path for loop detection, and also (ultimately) pass it to
dwfl_core_file_report(). The latter seems to be fine will NULL, so let's just
change our code to look at COMM, which should be more reliable anyway.

Fixes https://bugzilla.redhat.com/show_bug.cgi?id=2036517.

src/coredump/coredump.c

index f7f2f194b4df7d75f3c7da5d6351a27867a5e160..3e38efe55298c69f03bf89e54c7cd5f437b30362 100644 (file)
@@ -812,16 +812,19 @@ static int submit_coredump(
                 return log_error_errno(r, "Failed to drop privileges: %m");
 
         /* Try to get a stack trace if we can */
-        if (coredump_size > arg_process_size_max) {
+        if (coredump_size > arg_process_size_max)
                 log_debug("Not generating stack trace: core size %"PRIu64" is greater "
                           "than %"PRIu64" (the configured maximum)",
                           coredump_size, arg_process_size_max);
-        } else if (coredump_fd >= 0)
+        else if (coredump_fd >= 0) {
+                bool skip = startswith(context->meta[META_COMM], "systemd-coredum"); /* COMM is 16 bytes usually */
+
                 (void) parse_elf_object(coredump_fd,
                                         context->meta[META_EXE],
-                                        /* fork_disable_dump= */endswith(context->meta[META_EXE], "systemd-coredump"), /* avoid loops */
+                                        /* fork_disable_dump= */ skip, /* avoid loops */
                                         &stacktrace,
                                         &json_metadata);
+        }
 
 log:
         core_message = strjoina("Process ", context->meta[META_ARGV_PID],
@@ -856,21 +859,24 @@ log:
                 (void) iovw_put_string_field(iovw, "COREDUMP_PACKAGE_JSON=", formatted_json);
         }
 
-        JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, json_metadata) {
-                JsonVariant *package_name, *package_version;
+        /* In the unlikely scenario that context->meta[META_EXE] is not available,
+         * let's avoid guessing the module name and skip the loop. */
+        if (context->meta[META_EXE])
+                JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, json_metadata) {
+                        JsonVariant *t;
 
-                /* We only add structured fields for the 'main' ELF module */
-                if (!path_equal_filename(module_name, context->meta[META_EXE]))
-                        continue;
+                        /* We only add structured fields for the 'main' ELF module, and only if we can identify it. */
+                        if (!path_equal_filename(module_name, context->meta[META_EXE]))
+                                continue;
 
-                package_name = json_variant_by_key(module_json, "name");
-                if (package_name)
-                        (void) iovw_put_string_field(iovw, "COREDUMP_PACKAGE_NAME=", json_variant_string(package_name));
+                        t = json_variant_by_key(module_json, "name");
+                        if (t)
+                                (void) iovw_put_string_field(iovw, "COREDUMP_PACKAGE_NAME=", json_variant_string(t));
 
-                package_version = json_variant_by_key(module_json, "version");
-                if (package_version)
-                        (void) iovw_put_string_field(iovw, "COREDUMP_PACKAGE_VERSION=", json_variant_string(package_version));
-        }
+                        t = json_variant_by_key(module_json, "version");
+                        if (t)
+                                (void) iovw_put_string_field(iovw, "COREDUMP_PACKAGE_VERSION=", json_variant_string(t));
+                }
 
         /* Optionally store the entire coredump in the journal */
         if (arg_storage == COREDUMP_STORAGE_JOURNAL && coredump_fd >= 0) {
@@ -1180,7 +1186,7 @@ static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
         if (r < 0)
                 return r;
 
-        /* The following are optional but we used them if present */
+        /* The following are optional, but we use them if present. */
         r = get_process_exe(pid, &t);
         if (r >= 0)
                 r = iovw_put_string_field_free(iovw, "COREDUMP_EXE=", t);
@@ -1190,7 +1196,6 @@ static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
         if (cg_pid_get_unit(pid, &t) >= 0)
                 (void) iovw_put_string_field_free(iovw, "COREDUMP_UNIT=", t);
 
-        /* The next are optional */
         if (cg_pid_get_user_unit(pid, &t) >= 0)
                 (void) iovw_put_string_field_free(iovw, "COREDUMP_USER_UNIT=", t);