]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/coredump/coredump.c
tree-wide: use memstream-util
[thirdparty/systemd.git] / src / coredump / coredump.c
index b6f3a2f256fd7034258e0268ebd2f4b2e684cf73..b355970f0ffa61b27eed8f12dd23280b2d990f27 100644 (file)
@@ -36,6 +36,7 @@
 #include "macro.h"
 #include "main-func.h"
 #include "memory-util.h"
+#include "memstream-util.h"
 #include "mkdir-label.h"
 #include "parse-util.h"
 #include "process-util.h"
@@ -171,14 +172,9 @@ static int parse_config(void) {
                 {}
         };
 
-        return config_parse_many_nulstr(
-                        PKGSYSCONFDIR "/coredump.conf",
-                        CONF_PATHS_NULSTR("systemd/coredump.conf.d"),
-                        "Coredump\0",
-                        config_item_table_lookup, items,
-                        CONFIG_PARSE_WARN,
-                        NULL,
-                        NULL);
+        return config_parse_config_file("coredump.conf", "Coredump\0",
+                                        config_item_table_lookup, items,
+                                        CONFIG_PARSE_WARN, NULL);
 }
 
 static uint64_t storage_size_max(void) {
@@ -251,7 +247,7 @@ static int fix_xattr(int fd, const Context *context) {
 #define filename_escape(s) xescape((s), "./ ")
 
 static const char *coredump_tmpfile_name(const char *s) {
-        return s ? s : "(unnamed temporary file)";
+        return s ?: "(unnamed temporary file)";
 }
 
 static int fix_permissions(
@@ -277,7 +273,7 @@ static int fix_permissions(
         if (r < 0)
                 return log_error_errno(r, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename));
 
-        r = link_tmpfile(fd, filename, target);
+        r = link_tmpfile(fd, filename, target, /* replace= */ false);
         if (r < 0)
                 return log_error_errno(r, "Failed to move coredump %s into place: %m", target);
 
@@ -340,96 +336,6 @@ static int make_filename(const Context *context, char **ret) {
         return 0;
 }
 
-static int parse_auxv64(
-                const uint64_t *auxv,
-                size_t size_bytes,
-                int *at_secure,
-                uid_t *uid,
-                uid_t *euid,
-                gid_t *gid,
-                gid_t *egid) {
-
-        assert(auxv || size_bytes == 0);
-
-        if (size_bytes % (2 * sizeof(uint64_t)) != 0)
-                return log_warning_errno(SYNTHETIC_ERRNO(EIO), "Incomplete auxv structure (%zu bytes).", size_bytes);
-
-        size_t words = size_bytes / sizeof(uint64_t);
-
-        /* Note that we set output variables even on error. */
-
-        for (size_t i = 0; i + 1 < words; i += 2)
-                switch (auxv[i]) {
-                case AT_SECURE:
-                        *at_secure = auxv[i + 1] != 0;
-                        break;
-                case AT_UID:
-                        *uid = auxv[i + 1];
-                        break;
-                case AT_EUID:
-                        *euid = auxv[i + 1];
-                        break;
-                case AT_GID:
-                        *gid = auxv[i + 1];
-                        break;
-                case AT_EGID:
-                        *egid = auxv[i + 1];
-                        break;
-                case AT_NULL:
-                        if (auxv[i + 1] != 0)
-                                goto error;
-                        return 0;
-                }
- error:
-        return log_warning_errno(SYNTHETIC_ERRNO(ENODATA),
-                                 "AT_NULL terminator not found, cannot parse auxv structure.");
-}
-
-static int parse_auxv32(
-                const uint32_t *auxv,
-                size_t size_bytes,
-                int *at_secure,
-                uid_t *uid,
-                uid_t *euid,
-                gid_t *gid,
-                gid_t *egid) {
-
-        assert(auxv || size_bytes == 0);
-
-        size_t words = size_bytes / sizeof(uint32_t);
-
-        if (size_bytes % (2 * sizeof(uint32_t)) != 0)
-                return log_warning_errno(SYNTHETIC_ERRNO(EIO), "Incomplete auxv structure (%zu bytes).", size_bytes);
-
-        /* Note that we set output variables even on error. */
-
-        for (size_t i = 0; i + 1 < words; i += 2)
-                switch (auxv[i]) {
-                case AT_SECURE:
-                        *at_secure = auxv[i + 1] != 0;
-                        break;
-                case AT_UID:
-                        *uid = auxv[i + 1];
-                        break;
-                case AT_EUID:
-                        *euid = auxv[i + 1];
-                        break;
-                case AT_GID:
-                        *gid = auxv[i + 1];
-                        break;
-                case AT_EGID:
-                        *egid = auxv[i + 1];
-                        break;
-                case AT_NULL:
-                        if (auxv[i + 1] != 0)
-                                goto error;
-                        return 0;
-                }
- error:
-        return log_warning_errno(SYNTHETIC_ERRNO(ENODATA),
-                                 "AT_NULL terminator not found, cannot parse auxv structure.");
-}
-
 static int grant_user_access(int core_fd, const Context *context) {
         int at_secure = -1;
         uid_t uid = UID_INVALID, euid = UID_INVALID;
@@ -464,14 +370,11 @@ static int grant_user_access(int core_fd, const Context *context) {
                 return log_info_errno(SYNTHETIC_ERRNO(EUCLEAN),
                                       "Core file has non-native endianness, not adjusting permissions.");
 
-        if (elf[EI_CLASS] == ELFCLASS64)
-                r = parse_auxv64((const uint64_t*) context->meta[META_PROC_AUXV],
-                                 context->meta_size[META_PROC_AUXV],
-                                 &at_secure, &uid, &euid, &gid, &egid);
-        else
-                r = parse_auxv32((const uint32_t*) context->meta[META_PROC_AUXV],
-                                 context->meta_size[META_PROC_AUXV],
-                                 &at_secure, &uid, &euid, &gid, &egid);
+        r = parse_auxv(LOG_WARNING,
+                       /* elf_class= */ elf[EI_CLASS],
+                       context->meta[META_PROC_AUXV],
+                       context->meta_size[META_PROC_AUXV],
+                       &at_secure, &uid, &euid, &gid, &egid);
         if (r < 0)
                 return r;
 
@@ -499,7 +402,7 @@ static int save_external_coredump(
 
         _cleanup_(unlink_and_freep) char *tmp = NULL;
         _cleanup_free_ char *fn = NULL;
-        _cleanup_close_ int fd = -1;
+        _cleanup_close_ int fd = -EBADF;
         uint64_t rlimit, process_limit, max_size;
         bool truncated, storage_on_tmpfs;
         struct stat st;
@@ -597,7 +500,7 @@ static int save_external_coredump(
                 /* tmpfs might get full quickly, so check the available space too.
                  * But don't worry about errors here, failing to access the storage
                  * location will be better logged when writing to it. */
-                if (statvfs("/var/lib/systemd/coredump/", &sv) >= 0)
+                if (fstatvfs(fd, &sv) >= 0)
                         max_size = MIN((uint64_t)sv.f_frsize * (uint64_t)sv.f_bfree, max_size);
 
                 log_debug("Limiting core file size to %" PRIu64 " bytes due to cgroup memory limits.", max_size);
@@ -615,7 +518,7 @@ static int save_external_coredump(
         if (arg_compress) {
                 _cleanup_(unlink_and_freep) char *tmp_compressed = NULL;
                 _cleanup_free_ char *fn_compressed = NULL;
-                _cleanup_close_ int fd_compressed = -1;
+                _cleanup_close_ int fd_compressed = -EBADF;
                 uint64_t uncompressed_size = 0;
 
                 if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
@@ -739,17 +642,16 @@ static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_s
  * flags:  0100002
  * EOF
  */
-static int compose_open_fds(pid_t pid, char **open_fds) {
+static int compose_open_fds(pid_t pid, char **ret) {
+        _cleanup_(memstream_done) MemStream m = {};
         _cleanup_closedir_ DIR *proc_fd_dir = NULL;
-        _cleanup_close_ int proc_fdinfo_fd = -1;
-        _cleanup_free_ char *buffer = NULL;
-        _cleanup_fclose_ FILE *stream = NULL;
+        _cleanup_close_ int proc_fdinfo_fd = -EBADF;
         const char *fddelim = "", *path;
-        size_t size = 0;
+        FILE *stream;
         int r;
 
         assert(pid >= 0);
-        assert(open_fds != NULL);
+        assert(ret);
 
         path = procfs_file_alloca(pid, "fd");
         proc_fd_dir = opendir(path);
@@ -760,14 +662,14 @@ static int compose_open_fds(pid_t pid, char **open_fds) {
         if (proc_fdinfo_fd < 0)
                 return -errno;
 
-        stream = open_memstream_unlocked(&buffer, &size);
+        stream = memstream_init(&m);
         if (!stream)
                 return -ENOMEM;
 
         FOREACH_DIRENT(de, proc_fd_dir, return -errno) {
                 _cleanup_fclose_ FILE *fdinfo = NULL;
                 _cleanup_free_ char *fdname = NULL;
-                _cleanup_close_ int fd = -1;
+                _cleanup_close_ int fd = -EBADF;
 
                 r = readlinkat_malloc(dirfd(proc_fd_dir), de->d_name, &fdname);
                 if (r < 0)
@@ -799,21 +701,13 @@ static int compose_open_fds(pid_t pid, char **open_fds) {
                 }
         }
 
-        errno = 0;
-        stream = safe_fclose(stream);
-
-        if (errno > 0)
-                return -errno;
-
-        *open_fds = TAKE_PTR(buffer);
-
-        return 0;
+        return memstream_finalize(&m, ret, NULL);
 }
 
 static int get_process_ns(pid_t pid, const char *namespace, ino_t *ns) {
         const char *p;
         struct stat stbuf;
-        _cleanup_close_ int proc_ns_dir_fd = -1;
+        _cleanup_close_ int proc_ns_dir_fd = -EBADF;
 
         p = procfs_file_alloca(pid, "ns");
 
@@ -928,7 +822,7 @@ static int submit_coredump(
                 int input_fd) {
 
         _cleanup_(json_variant_unrefp) JsonVariant *json_metadata = NULL;
-        _cleanup_close_ int coredump_fd = -1, coredump_node_fd = -1;
+        _cleanup_close_ int coredump_fd = -EBADF, coredump_node_fd = -EBADF;
         _cleanup_free_ char *filename = NULL, *coredump_data = NULL;
         _cleanup_free_ char *stacktrace = NULL;
         char *core_message;
@@ -1132,7 +1026,7 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
 }
 
 static int process_socket(int fd) {
-        _cleanup_close_ int input_fd = -1;
+        _cleanup_close_ int input_fd = -EBADF;
         Context context = {};
         struct iovec_wrapper iovw = {};
         struct iovec iovec;
@@ -1192,7 +1086,7 @@ static int process_socket(int fd) {
                         }
 
                         assert(input_fd < 0);
-                        input_fd = *(int*) CMSG_DATA(found);
+                        input_fd = *CMSG_TYPED_DATA(found, int);
                         break;
                 } else
                         cmsg_close_all(&mh);
@@ -1230,7 +1124,7 @@ finish:
 }
 
 static int send_iovec(const struct iovec_wrapper *iovw, int input_fd) {
-        _cleanup_close_ int fd = -1;
+        _cleanup_close_ int fd = -EBADF;
         int r;
 
         assert(iovw);
@@ -1463,7 +1357,7 @@ static int process_kernel(int argc, char* argv[]) {
         /* When we're invoked by the kernel, stdout/stderr are closed which is dangerous because the fds
          * could get reallocated. To avoid hard to debug issues, let's instead bind stdout/stderr to
          * /dev/null. */
-        r = rearrange_stdio(STDIN_FILENO, -1, -1);
+        r = rearrange_stdio(STDIN_FILENO, -EBADF, -EBADF);
         if (r < 0)
                 return log_error_errno(r, "Failed to connect stdout/stderr to /dev/null: %m");
 
@@ -1486,11 +1380,9 @@ static int process_kernel(int argc, char* argv[]) {
         if (r < 0)
                 goto finish;
 
-        if (!context.is_journald) {
+        if (!context.is_journald)
                 /* 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();
-        }
+                log_set_target_and_open(LOG_TARGET_JOURNAL_OR_KMSG);
 
         /* If this is PID 1 disable coredump collection, we'll unlikely be able to process
          * it later on.
@@ -1589,8 +1481,7 @@ static int run(int argc, char *argv[]) {
         /* First, log to a safe place, since we don't know what crashed and it might
          * be journald which we'd rather not log to then. */
 
-        log_set_target(LOG_TARGET_KMSG);
-        log_open();
+        log_set_target_and_open(LOG_TARGET_KMSG);
 
         /* Make sure we never enter a loop */
         (void) prctl(PR_SET_DUMPABLE, 0);