X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fjournal%2Fcoredump.c;h=7dea66e6fdd74bd4e396943cbb266a4efe587c1b;hp=bbec550784f8a79855c3808140af67c4092ae0ab;hb=b070e7f3c9ed680c821bd89d42506695f2438506;hpb=de0229ca36034981f6c380de39bf7ffd3c6b57fa diff --git a/src/journal/coredump.c b/src/journal/coredump.c index bbec55078..7dea66e6f 100644 --- a/src/journal/coredump.c +++ b/src/journal/coredump.c @@ -21,12 +21,15 @@ #include #include +#include +#include #include #include #include "log.h" #include "util.h" +#include "special.h" #define COREDUMP_MAX (24*1024*1024) @@ -40,21 +43,74 @@ enum { _ARG_MAX }; +static int divert_coredump(void) { + FILE *f; + int r; + + log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/."); + + mkdir_p("/var/lib/systemd/coredump", 0755); + + f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we"); + if (!f) { + log_error("Failed to create coredump file: %m"); + return -errno; + } + + for (;;) { + uint8_t buffer[4096]; + size_t l, q; + + l = fread(buffer, 1, sizeof(buffer), stdin); + if (l <= 0) { + if (ferror(f)) { + log_error("Failed to read coredump: %m"); + r = -errno; + goto finish; + } + + r = 0; + break; + } + + q = fwrite(buffer, 1, l, f); + if (q != l) { + log_error("Failed to write coredump: %m"); + r = -errno; + goto finish; + } + } + + fflush(f); + + if (ferror(f)) { + log_error("Failed to write coredump: %m"); + r = -errno; + } + +finish: + fclose(f); + return r; +} + int main(int argc, char* argv[]) { int r, j = 0; char *p = NULL; ssize_t n; pid_t pid; + uid_t uid; + gid_t gid; struct iovec iovec[14]; 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; - log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); - log_parse_environment(); - log_open(); + prctl(PR_SET_DUMPABLE, 0); if (argc != _ARG_MAX) { + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_open(); + log_error("Invalid number of arguments passed from kernel."); r = -EINVAL; goto finish; @@ -62,31 +118,48 @@ int main(int argc, char* argv[]) { r = parse_pid(argv[ARG_PID], &pid); if (r < 0) { + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_open(); + log_error("Failed to parse PID."); - r = -EINVAL; goto finish; } - p = malloc(9 + COREDUMP_MAX); - if (!p) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; + if (sd_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); + free(t); + + if (core_unit) + IOVEC_SET_STRING(iovec[j++], core_unit); } - memcpy(p, "COREDUMP=", 9); + /* OK, now we know it's not the journal, hence make use of + * it */ + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_open(); - 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; + r = parse_uid(argv[ARG_UID], &uid); + if (r < 0) { + log_error("Failed to parse UID."); goto finish; } - zero(iovec); - iovec[j].iov_base = p; - iovec[j].iov_len = 9 + n; - j++; + r = parse_gid(argv[ARG_GID], &gid); + if (r < 0) { + log_error("Failed to parse GID."); + goto finish; + } core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]); if (core_pid) @@ -116,14 +189,6 @@ int main(int argc, char* argv[]) { IOVEC_SET_STRING(iovec[j++], core_session); } - if (sd_pid_get_unit(pid, &t) >= 0) { - core_unit = strappend("COREDUMP_UNIT=", t); - free(t); - - if (core_unit) - IOVEC_SET_STRING(iovec[j++], core_unit); - } - if (get_process_exe(pid, &t) >= 0) { core_exe = strappend("COREDUMP_EXE=", t); free(t); @@ -151,6 +216,39 @@ int main(int argc, char* argv[]) { if (core_message) IOVEC_SET_STRING(iovec[j++], core_message); + /* Now, let's drop privileges to become the user who owns the + * segfaulted process and allocate the coredump memory under + * his uid. This also ensures that the credentials journald + * will see are the ones of the coredumping user, thus making + * sure the user himself gets access to the core dump. */ + + if (setresgid(gid, gid, gid) < 0 || + setresuid(uid, uid, uid) < 0) { + log_error("Failed to drop privileges: %m"); + r = -errno; + goto finish; + } + + p = malloc(9 + COREDUMP_MAX); + if (!p) { + log_error("Out of memory"); + r = -ENOMEM; + 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); if (r < 0) log_error("Failed to send coredump: %s", strerror(-r));