]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/coredump/coredump.c
basic/process-util: convert bool arg to flags
[thirdparty/systemd.git] / src / coredump / coredump.c
index d3fc059fbb5733b4d2af2ddf854d51098726feaa..2cceb49f4b1aa05b51a210cb357f6dd81fa0d29a 100644 (file)
@@ -2,7 +2,6 @@
 
 #include <errno.h>
 #include <stdio.h>
-#include <stdio_ext.h>
 #include <sys/prctl.h>
 #include <sys/xattr.h>
 #include <unistd.h>
@@ -34,6 +33,8 @@
 #include "journal-importer.h"
 #include "log.h"
 #include "macro.h"
+#include "main-func.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "mkdir.h"
 #include "parse-util.h"
@@ -45,8 +46,8 @@
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tmpfile-util.h"
 #include "user-util.h"
-#include "util.h"
 
 /* The maximum size up to which we process coredumps */
 #define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU))
 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
 
 /* The maximum size up to which we store the coredump in the journal */
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
+#else
+/* oss-fuzz limits memory usage. */
+#define JOURNAL_SIZE_MAX ((size_t) (10LU*1024LU*1024LU))
+#endif
 
 /* Make sure to not make this larger than the maximum journal entry
- * size. See DATA_SIZE_MAX in journald-native.c. */
+ * size. See DATA_SIZE_MAX in journal-importer.h. */
 assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
 
 enum {
@@ -135,7 +141,7 @@ static int parse_config(void) {
                                         CONFIG_PARSE_WARN, NULL);
 }
 
-static inline uint64_t storage_size_max(void) {
+static uint64_t storage_size_max(void) {
         if (arg_storage == COREDUMP_STORAGE_EXTERNAL)
                 return arg_external_size_max;
         if (arg_storage == COREDUMP_STORAGE_JOURNAL)
@@ -222,7 +228,7 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {
 
 #define filename_escape(s) xescape((s), "./ ")
 
-static inline const char *coredump_tmpfile_name(const char *s) {
+static const char *coredump_tmpfile_name(const char *s) {
         return s ? s : "(unnamed temporary file)";
 }
 
@@ -340,21 +346,20 @@ static int save_external_coredump(
 
         r = safe_atou64(context[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': %m", context[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]);
-                return -EBADSLT;
+                return log_info_errno(SYNTHETIC_ERRNO(EBADSLT),
+                                      "Resource limits disable core dumping for process %s (%s).",
+                                      context[CONTEXT_PID], context[CONTEXT_COMM]);
         }
 
         process_limit = MAX(arg_process_size_max, storage_size_max());
-        if (process_limit == 0) {
-                log_debug("Limits for coredump processing and storage are both 0, not dumping core.");
-                return -EBADSLT;
-        }
+        if (process_limit == 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EBADSLT),
+                                       "Limits for coredump processing and storage are both 0, not dumping core.");
 
         /* Never store more than the process configured, or than we actually shall keep or process */
         max_size = MIN(rlimit, process_limit);
@@ -363,7 +368,7 @@ static int save_external_coredump(
         if (r < 0)
                 return log_error_errno(r, "Failed to determine coredump file name: %m");
 
-        mkdir_p_label("/var/lib/systemd/coredump", 0755);
+        (void) mkdir_p_label("/var/lib/systemd/coredump", 0755);
 
         fd = open_tmpfile_linkable(fn, O_RDWR|O_CLOEXEC, &tmp);
         if (fd < 0)
@@ -478,10 +483,9 @@ static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_s
         n = read(fd, field + 9, size);
         if (n < 0)
                 return log_error_errno((int) n, "Failed to read core data: %m");
-        if ((size_t) n < size) {
-                log_error("Core data too short.");
-                return -EIO;
-        }
+        if ((size_t) n < size)
+                return log_error_errno(SYNTHETIC_ERRNO(EIO),
+                                       "Core data too short.");
 
         *ret = TAKE_PTR(field);
         *ret_size = size + 9;
@@ -525,12 +529,10 @@ static int compose_open_fds(pid_t pid, char **open_fds) {
         if (proc_fdinfo_fd < 0)
                 return -errno;
 
-        stream = open_memstream(&buffer, &size);
+        stream = open_memstream_unlocked(&buffer, &size);
         if (!stream)
                 return -ENOMEM;
 
-        (void) __fsetlocking(stream, FSETLOCKING_BYCALLER);
-
         FOREACH_DIRENT(dent, proc_fd_dir, return -errno) {
                 _cleanup_fclose_ FILE *fdinfo = NULL;
                 _cleanup_free_ char *fdname = NULL;
@@ -548,7 +550,7 @@ static int compose_open_fds(pid_t pid, char **open_fds) {
                 if (fd < 0)
                         continue;
 
-                fdinfo = fdopen(fd, "re");
+                fdinfo = fdopen(fd, "r");
                 if (!fdinfo) {
                         safe_close(fd);
                         continue;
@@ -659,7 +661,7 @@ static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) {
         if (r < 0)
                 return r;
 
-        r = get_process_cmdline(container_pid, 0, false, cmdline);
+        r = get_process_cmdline(container_pid, SIZE_MAX, 0, cmdline);
         if (r < 0)
                 return r;
 
@@ -763,7 +765,7 @@ static int submit_coredump(
                 return log_error_errno(r, "Failed to drop privileges: %m");
 
 #if HAVE_ELFUTILS
-        /* Try to get a strack trace if we can */
+        /* Try to get a stack trace if we can */
         if (coredump_size <= arg_process_size_max) {
                 _cleanup_free_ char *stacktrace = NULL;
 
@@ -789,15 +791,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;
         }
 
@@ -877,9 +880,7 @@ static int process_socket(int fd) {
 
         assert(fd >= 0);
 
-        log_set_target(LOG_TARGET_AUTO);
-        log_parse_environment();
-        log_open();
+        log_setup_service();
 
         log_debug("Processing coredump received on stdin...");
 
@@ -1035,10 +1036,7 @@ static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd)
                                          * (truncated) copy of what we want to send, and the second one
                                          * contains the trailing dots. */
                                         copy[0] = iovec[i];
-                                        copy[1] = (struct iovec) {
-                                                .iov_base = (char[]) { '.', '.', '.' },
-                                                .iov_len = 3,
-                                        };
+                                        copy[1] = IOVEC_MAKE(((char[]){'.', '.', '.'}), 3);
 
                                         mh.msg_iov = copy;
                                         mh.msg_iovlen = 2;
@@ -1059,19 +1057,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;
 }
@@ -1121,36 +1110,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)
@@ -1165,7 +1154,7 @@ static int gather_pid_metadata(
         if (sd_pid_get_slice(pid, &t) >= 0)
                 set_iovec_field_free(iovec, n_iovec, "COREDUMP_SLICE=", t);
 
-        if (get_process_cmdline(pid, 0, false, &t) >= 0)
+        if (get_process_cmdline(pid, SIZE_MAX, 0, &t) >= 0)
                 set_iovec_field_free(iovec, n_iovec, "COREDUMP_CMDLINE=", t);
 
         if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0)
@@ -1218,7 +1207,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 */
 }
@@ -1232,10 +1221,10 @@ static int process_kernel(int argc, char* argv[]) {
 
         log_debug("Processing coredump received from the kernel...");
 
-        if (argc < CONTEXT_COMM + 1) {
-                log_error("Not enough arguments passed by the kernel (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1);
-                return -EINVAL;
-        }
+        if (argc < CONTEXT_COMM + 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Not enough arguments passed by the kernel (%i, expected %i).",
+                                       argc - 1, CONTEXT_COMM + 1 - 1);
 
         context[CONTEXT_PID]       = argv[1 + CONTEXT_PID];
         context[CONTEXT_UID]       = argv[1 + CONTEXT_UID];
@@ -1289,10 +1278,10 @@ static int process_backtrace(int argc, char *argv[]) {
 
         log_debug("Processing backtrace on stdin...");
 
-        if (argc < CONTEXT_COMM + 1) {
-                log_error("Not enough arguments passed (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1);
-                return -EINVAL;
-        }
+        if (argc < CONTEXT_COMM + 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Not enough arguments passed (%i, expected %i).",
+                                       argc - 1, CONTEXT_COMM + 1 - 1);
 
         context[CONTEXT_PID]       = argv[2 + CONTEXT_PID];
         context[CONTEXT_UID]       = argv[2 + CONTEXT_UID];
@@ -1371,7 +1360,7 @@ static int process_backtrace(int argc, char *argv[]) {
         return r;
 }
 
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
         int r;
 
         /* First, log to a safe place, since we don't know what crashed and it might
@@ -1390,25 +1379,21 @@ int main(int argc, char *argv[]) {
         log_debug("Selected compression %s.", yes_no(arg_compress));
 
         r = sd_listen_fds(false);
-        if (r < 0) {
-                log_error_errno(r, "Failed to determine number of file descriptor: %m");
-                goto finish;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine the number of file descriptors: %m");
 
         /* If we got an fd passed, we are running in coredumpd mode. Otherwise we
          * are invoked from the kernel as coredump handler. */
         if (r == 0) {
                 if (streq_ptr(argv[1], "--backtrace"))
-                        r = process_backtrace(argc, argv);
+                        return process_backtrace(argc, argv);
                 else
-                        r = process_kernel(argc, argv);
+                        return process_kernel(argc, argv);
         } else if (r == 1)
-                r = process_socket(SD_LISTEN_FDS_START);
-        else {
-                log_error("Received unexpected number of file descriptors.");
-                r = -EINVAL;
-        }
+                return process_socket(SD_LISTEN_FDS_START);
 
-finish:
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                               "Received unexpected number of file descriptors.");
 }
+
+DEFINE_MAIN_FUNCTION(run);