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 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel