[systemd-devel] [PATCH] [RFC] Optionaly save coredump to file

Oleksii Shevchuk alxchk at gmail.com
Fri Feb 8 14:47:05 PST 2013


Dump coredump to /var/log/journal/MACHINE-ID/coredump/COMM.DUMP-ID128.
If can't, fallback to default behavior (dump to journal 24Mb of data).

Optionaly introduce SHA1 hashsum for incoming coredumps, if they are
going out of journal
---
 Makefile.am                   |  10 ++
 src/journal/coredump.c        | 263 +++++++++++++++++++++++++++++++-----------
 src/journal/journald-server.h |   2 +-
 src/shared/util.c             |  23 ++++
 src/shared/util.h             |   1 +
 5 files changed, 232 insertions(+), 67 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 163e8f8..8cf3686 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2644,6 +2644,7 @@ systemd_coredump_SOURCES = \
 
 systemd_coredump_LDADD = \
 	libsystemd-journal-internal.la \
+	libsystemd-id128-internal.la \
 	libsystemd-label.la \
 	libsystemd-shared.la
 
@@ -2652,6 +2653,15 @@ systemd_coredump_LDADD += \
 	libsystemd-login-internal.la
 endif
 
+if HAVE_GCRYPT
+systemd_coredump_CFLAGS = \
+	$(GCRYPT_CFLAGS) \
+	-Wno-pointer-arith
+
+systemd_coredump_LDADD += \
+	$(GCRYPT_LIBS)
+endif
+
 rootlibexec_PROGRAMS += \
 	systemd-coredump
 
diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index 021b4c6..06fad24 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -24,6 +24,10 @@
 #include <stdio.h>
 #include <sys/prctl.h>
 
+#if defined(HAVE_GCRYPT)
+#include <gcrypt.h>
+#endif
+
 #include <systemd/sd-journal.h>
 
 #ifdef HAVE_LOGIND
@@ -35,6 +39,7 @@
 #include "macro.h"
 #include "mkdir.h"
 #include "special.h"
+#include "sd-id128.h"
 #include "cgroup-util.h"
 
 #define COREDUMP_MAX (24*1024*1024)
@@ -49,61 +54,215 @@ enum {
         _ARG_MAX
 };
 
-static int divert_coredump(void) {
-        _cleanup_fclose_ FILE *f = NULL;
+#if defined(HAVE_GCRYPT)
+static void gcry_md_closep(gcry_md_hd_t *p)
+{
+        gcry_md_close(*p);
+}
+#endif
+
+static int submit_process_core(struct iovec iovec[15], int idx,
+                               const char * comm,
+                               const int journal)
+{
+        int r = EXIT_FAILURE;
 
-        log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/.");
+        _cleanup_fclose_ FILE * corefile = NULL;
+        _cleanup_free_   char * corepath = NULL;
+        _cleanup_free_   char * corelink = NULL;
+        _cleanup_free_   char * t = NULL;
 
-        mkdir_p_label("/var/lib/systemd/coredump", 0755);
+#if defined(HAVE_GCRYPT)
+        _cleanup_free_   char * h = NULL;
+#endif
 
-        f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we");
-        if (!f) {
-                log_error("Failed to create coredump file: %m");
-                return -errno;
+        if (journal) {
+                mkdir_p_label("/var/lib/systemd/coredump", 0755);
+                corelink = strdup("/var/lib/systemd/coredump/core.systemd-journald");
+                if (! corelink) {
+                        r = log_oom();
+                        goto finish;
+                }
+
+                corepath = strdup(corelink);
+                if (! corepath) {
+                        r = log_oom();
+                        goto finish;
+                }
+        } else {
+                _cleanup_free_ char * c;
+
+                char buffer[33];
+                sd_id128_t coreid;
+                sd_id128_t machineid;
+
+                const char *p = strrchr(comm, '/');
+                if (p)
+                        p ++;
+                else
+                        p = comm;
+
+                r = sd_id128_get_machine(&machineid);
+                if (r)
+                        goto finish;
+
+                c = sd_id128_to_string(machineid, buffer);
+                c = strjoin("/var/log/journal/", c, "/coredump", NULL);
+                if (! c)
+                        goto finish;
+
+                r = access(c, X_OK | W_OK);
+                if (r)
+                        goto finish;
+
+                r = sd_id128_randomize(&coreid);
+                if (r)
+                        goto finish;
+
+                corelink = strjoin(p, ".", sd_id128_to_string(coreid, buffer), NULL);
+                if (! corelink)
+                        goto finish;
+
+                corepath = strjoin(c, "/", corelink, NULL);
+                if (! corepath)
+                        goto finish;
         }
 
-        for (;;) {
-                uint8_t buffer[4096];
-                size_t l, q;
+        corefile = fopen(corepath, "w");
+
+        if (! corefile) {
+                if (journal) {
+                        log_error("Failed to create coredump file: %m");
+                        goto finish;
+                }
+                else {
+                        int n;
+
+                        IOVEC_SET_STRING(iovec[idx++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
+
+                        t = malloc(9 + COREDUMP_MAX);
+                        if (!t) {
+                                r = log_oom();
+                                goto finish;
+                        }
+
+                        memcpy(t, "COREDUMP=", 9);
 
-                l = fread(buffer, 1, sizeof(buffer), stdin);
-                if (l <= 0) {
-                        if (ferror(f)) {
-                                log_error("Failed to read coredump: %m");
-                                return -errno;
+                        n = loop_read(STDIN_FILENO, t + 9, COREDUMP_MAX, false);
+                        if (n < 0) {
+                                log_error("Failed to read core dump data: %s", strerror(-n));
+                                r = (int) n;
+                                goto finish;
                         }
 
-                        break;
+                        iovec[idx].iov_base = t;
+                        iovec[idx].iov_len = 9 + n;
+                        idx ++;
+                }
+        }
+        else {
+                r = chmod(corepath, 0600);
+                if (r) {
+                        log_debug("chmod %s: %s", corepath, strerror(errno));
+                }
+
+#if defined(HAVE_GCRYPT)
+                /* initialize_libgcrypt(); */
+
+                __attribute__((cleanup(gcry_md_closep)))
+                gcry_md_hd_t HD;
+                gcry_error_t gr = gcry_md_open (&HD, GCRY_MD_SHA1, 0);
+                if (gr != GPG_ERR_NO_ERROR) {
+                        log_error("Failed to initialize gcrypt hash context: %s",
+                                  gpg_strerror(gr));
+                        goto finish;
                 }
+#endif
+                for (;;) {
+                        uint8_t buffer[4096];
+                        size_t l, q;
+
+                        l = fread(buffer, 1, sizeof(buffer), stdin);
+                        if (l <= 0) {
+                                if (ferror(corefile)) {
+                                        log_error("Failed to read coredump: %m");
+                                        goto finish;
+                                }
+
+                                break;
+                        }
 
-                q = fwrite(buffer, 1, l, f);
-                if (q != l) {
+                        q = fwrite(buffer, 1, l, corefile);
+                        if (q != l) {
+                                log_error("Failed to write coredump: %m");
+                                goto finish;
+                        }
+
+#if defined(HAVE_GCRYPT)
+                        gcry_md_write(HD, buffer, l);
+#endif
+                }
+
+                fflush(corefile);
+
+                if (ferror(corefile)) {
                         log_error("Failed to write coredump: %m");
-                        return -errno;
                 }
-        }
 
-        fflush(f);
+                IOVEC_SET_STRING(iovec[idx++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b2");
+
+                if (journal) {
+                        log_error("Detected coredump of the journal daemon itself, coredump diverted to /var/lib/systemd/coredump/");
+                        r = EXIT_SUCCESS;
+                        goto finish;
+                }
+
+                t = strjoin("COREDUMP_FILE=coredump/", corelink, NULL);
+                if (t)
+                        IOVEC_SET_STRING(iovec[idx ++], t);
 
-        if (ferror(f)) {
-                log_error("Failed to write coredump: %m");
-                return -errno;
+#if defined(HAVE_GCRYPT)
+                char * bh = hexstr(gcry_md_read(HD, GCRY_MD_SHA1), 20);
+
+                if (! bh) {
+                        r = log_oom();
+                        goto finish;
+                }
+
+                h = strjoin("COREDUMP_FILE_SHA1=", bh, NULL);
+                free(bh);
+
+                if (! h) {
+                        r = log_oom();
+                        goto finish;
+                }
+
+                IOVEC_SET_STRING(iovec[idx ++], h);
+#endif
         }
 
-        return 0;
+        r = sd_journal_sendv(iovec, idx);
+        if (r < 0)
+                log_error("Failed to send coredump: %s", strerror(-r));
+
+ finish:
+        return r;
 }
 
 int main(int argc, char* argv[]) {
         int r, j = 0;
+        int journal = 0;
         _cleanup_free_ char *p = NULL;
-        ssize_t n;
         pid_t pid;
         uid_t uid;
         gid_t gid;
-        struct iovec iovec[14];
+        struct iovec iovec[15];
         _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
                 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
-                *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *t = NULL;
+                *core_session = NULL, *core_message = NULL, *core_cmdline = NULL,
+                *core_corelink = NULL;
+
+        char * t;
 
         prctl(PR_SET_DUMPABLE, 0);
 
@@ -126,27 +285,20 @@ int main(int argc, char* argv[]) {
         }
 
         if (cg_pid_get_unit(pid, &t) >= 0) {
-
-                if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
-                        /* Make sure we don't make use of the journal,
-                         * if it's the journal which is crashing */
-                        log_set_target(LOG_TARGET_KMSG);
-                        log_open();
-
-                        r = divert_coredump();
-                        goto finish;
-                }
-
                 core_unit = strappend("COREDUMP_UNIT=", t);
+                journal = streq(t, SPECIAL_JOURNALD_SERVICE);
         } else if (cg_pid_get_user_unit(pid, &t) >= 0)
                 core_unit = strappend("COREDUMP_USER_UNIT=", t);
+        free(t);
 
         if (core_unit)
                 IOVEC_SET_STRING(iovec[j++], core_unit);
 
-        /* OK, now we know it's not the journal, hence make use of
-         * it */
-        log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
+        if (journal)
+                log_set_target(LOG_TARGET_KMSG);
+        else
+                log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
+
         log_open();
 
         r = parse_uid(argv[ARG_UID], &uid);
@@ -191,7 +343,6 @@ int main(int argc, char* argv[]) {
         }
 
 #endif
-
         if (get_process_exe(pid, &t) >= 0) {
                 core_exe = strappend("COREDUMP_EXE=", t);
                 free(t);
@@ -212,7 +363,6 @@ int main(int argc, char* argv[]) {
         if (core_timestamp)
                 IOVEC_SET_STRING(iovec[j++], core_timestamp);
 
-        IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
         IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
 
         core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
@@ -232,28 +382,9 @@ int main(int argc, char* argv[]) {
                 goto finish;
         }
 
-        p = malloc(9 + COREDUMP_MAX);
-        if (!p) {
-                r = log_oom();
-                goto finish;
-        }
-
-        memcpy(p, "COREDUMP=", 9);
-
-        n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false);
-        if (n < 0) {
-                log_error("Failed to read core dump data: %s", strerror(-n));
-                r = (int) n;
-                goto finish;
-        }
-
-        iovec[j].iov_base = p;
-        iovec[j].iov_len = 9 + n;
-        j++;
-
-        r = sd_journal_sendv(iovec, j);
+        r = submit_process_core(iovec, j, argv[ARG_COMM], journal);
         if (r < 0)
-                log_error("Failed to send coredump: %s", strerror(-r));
+                log_error("Failed to store coredump: %s", strerror(-r));
 
 finish:
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index 9f50a29..3d05925 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -121,7 +121,7 @@ typedef struct Server {
         struct udev *udev;
 } Server;
 
-#define N_IOVEC_META_FIELDS 17
+#define N_IOVEC_META_FIELDS 18
 #define N_IOVEC_KERNEL_FIELDS 64
 #define N_IOVEC_UDEV_FIELDS 32
 
diff --git a/src/shared/util.c b/src/shared/util.c
index 969ef2b..a7eb343 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -1378,6 +1378,29 @@ char hexchar(int x) {
         return table[x & 15];
 }
 
+char * hexstr (const uint8_t *in, size_t count)
+{
+        char *r, *i = NULL;
+
+        if (!in || !count)
+                goto finish;
+
+        r = i = new(char, count * 2 + 1);
+        if (! r)
+                goto finish;
+
+        while (count--) {
+                *i++ = hexchar(*in >> 4);
+                *i++ = hexchar(*in);
+                ++in;
+        }
+
+        *i = '\0';
+
+ finish:
+        return r;
+}
+
 int unhexchar(char c) {
 
         if (c >= '0' && c <= '9')
diff --git a/src/shared/util.h b/src/shared/util.h
index 223617c..32a822d 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -211,6 +211,7 @@ int get_process_uid(pid_t pid, uid_t *uid);
 int get_process_gid(pid_t pid, gid_t *gid);
 
 char hexchar(int x);
+char * hexstr (const uint8_t *in, size_t count);
 int unhexchar(char c);
 char octchar(int x);
 int unoctchar(char c);
-- 
1.8.1.2



More information about the systemd-devel mailing list