1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/prctl.h>
27 #include <systemd/sd-journal.h>
28 #include <systemd/sd-login.h>
35 #define COREDUMP_MAX (24*1024*1024)
47 static int divert_coredump(void) {
51 log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/.");
53 mkdir_p("/var/lib/systemd/coredump", 0755);
55 f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we");
57 log_error("Failed to create coredump file: %m");
65 l = fread(buffer, 1, sizeof(buffer), stdin);
68 log_error("Failed to read coredump: %m");
77 q = fwrite(buffer, 1, l, f);
79 log_error("Failed to write coredump: %m");
88 log_error("Failed to write coredump: %m");
97 int main(int argc, char* argv[]) {
104 struct iovec iovec[14];
105 char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
106 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
107 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *t;
109 prctl(PR_SET_DUMPABLE, 0);
111 if (argc != _ARG_MAX) {
112 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
115 log_error("Invalid number of arguments passed from kernel.");
120 r = parse_pid(argv[ARG_PID], &pid);
122 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
125 log_error("Failed to parse PID.");
129 if (sd_pid_get_unit(pid, &t) >= 0) {
131 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
132 /* Make sure we don't make use of the journal,
133 * if it's the journal which is crashing */
134 log_set_target(LOG_TARGET_KMSG);
137 r = divert_coredump();
141 core_unit = strappend("COREDUMP_UNIT=", t);
145 IOVEC_SET_STRING(iovec[j++], core_unit);
148 /* OK, now we know it's not the journal, hence make use of
150 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
153 r = parse_uid(argv[ARG_UID], &uid);
155 log_error("Failed to parse UID.");
159 r = parse_gid(argv[ARG_GID], &gid);
161 log_error("Failed to parse GID.");
165 core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]);
167 IOVEC_SET_STRING(iovec[j++], core_pid);
169 core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]);
171 IOVEC_SET_STRING(iovec[j++], core_uid);
173 core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]);
175 IOVEC_SET_STRING(iovec[j++], core_gid);
177 core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]);
179 IOVEC_SET_STRING(iovec[j++], core_signal);
181 core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]);
183 IOVEC_SET_STRING(iovec[j++], core_comm);
185 if (sd_pid_get_session(pid, &t) >= 0) {
186 core_session = strappend("COREDUMP_SESSION=", t);
190 IOVEC_SET_STRING(iovec[j++], core_session);
193 if (get_process_exe(pid, &t) >= 0) {
194 core_exe = strappend("COREDUMP_EXE=", t);
198 IOVEC_SET_STRING(iovec[j++], core_exe);
201 if (get_process_cmdline(pid, LINE_MAX, false, &t) >= 0) {
202 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
206 IOVEC_SET_STRING(iovec[j++], core_cmdline);
209 core_timestamp = join("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL);
211 IOVEC_SET_STRING(iovec[j++], core_timestamp);
213 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
214 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
216 core_message = join("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
218 IOVEC_SET_STRING(iovec[j++], core_message);
220 /* Now, let's drop privileges to become the user who owns the
221 * segfaulted process and allocate the coredump memory under
222 * his uid. This also ensures that the credentials journald
223 * will see are the ones of the coredumping user, thus making
224 * sure the user himself gets access to the core dump. */
226 if (setresgid(gid, gid, gid) < 0 ||
227 setresuid(uid, uid, uid) < 0) {
228 log_error("Failed to drop privileges: %m");
233 p = malloc(9 + COREDUMP_MAX);
235 log_error("Out of memory");
240 memcpy(p, "COREDUMP=", 9);
242 n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false);
244 log_error("Failed to read core dump data: %s", strerror(-n));
249 iovec[j].iov_base = p;
250 iovec[j].iov_len = 9 + n;
253 r = sd_journal_sendv(iovec, j);
255 log_error("Failed to send coredump: %s", strerror(-r));
263 free(core_timestamp);
271 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;