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>
30 #include <systemd/sd-login.h>
37 #include "cgroup-util.h"
39 #define COREDUMP_MAX (24*1024*1024)
51 static int divert_coredump(void) {
55 log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/.");
57 mkdir_p_label("/var/lib/systemd/coredump", 0755);
59 f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we");
61 log_error("Failed to create coredump file: %m");
69 l = fread(buffer, 1, sizeof(buffer), stdin);
72 log_error("Failed to read coredump: %m");
81 q = fwrite(buffer, 1, l, f);
83 log_error("Failed to write coredump: %m");
92 log_error("Failed to write coredump: %m");
101 int main(int argc, char* argv[]) {
108 struct iovec iovec[14];
109 char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
110 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
111 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *t;
113 prctl(PR_SET_DUMPABLE, 0);
115 if (argc != _ARG_MAX) {
116 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
119 log_error("Invalid number of arguments passed from kernel.");
124 r = parse_pid(argv[ARG_PID], &pid);
126 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
129 log_error("Failed to parse PID.");
133 if (cg_pid_get_unit(pid, &t) >= 0) {
135 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
136 /* Make sure we don't make use of the journal,
137 * if it's the journal which is crashing */
138 log_set_target(LOG_TARGET_KMSG);
141 r = divert_coredump();
145 core_unit = strappend("COREDUMP_UNIT=", t);
147 } else if (cg_pid_get_user_unit(pid, &t) >= 0) {
148 core_unit = strappend("COREDUMP_USER_UNIT=", t);
153 IOVEC_SET_STRING(iovec[j++], core_unit);
155 /* OK, now we know it's not the journal, hence make use of
157 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
160 r = parse_uid(argv[ARG_UID], &uid);
162 log_error("Failed to parse UID.");
166 r = parse_gid(argv[ARG_GID], &gid);
168 log_error("Failed to parse GID.");
172 core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]);
174 IOVEC_SET_STRING(iovec[j++], core_pid);
176 core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]);
178 IOVEC_SET_STRING(iovec[j++], core_uid);
180 core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]);
182 IOVEC_SET_STRING(iovec[j++], core_gid);
184 core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]);
186 IOVEC_SET_STRING(iovec[j++], core_signal);
188 core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]);
190 IOVEC_SET_STRING(iovec[j++], core_comm);
193 if (sd_pid_get_session(pid, &t) >= 0) {
194 core_session = strappend("COREDUMP_SESSION=", t);
198 IOVEC_SET_STRING(iovec[j++], core_session);
203 if (get_process_exe(pid, &t) >= 0) {
204 core_exe = strappend("COREDUMP_EXE=", t);
208 IOVEC_SET_STRING(iovec[j++], core_exe);
211 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
212 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
216 IOVEC_SET_STRING(iovec[j++], core_cmdline);
219 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL);
221 IOVEC_SET_STRING(iovec[j++], core_timestamp);
223 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
224 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
226 core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
228 IOVEC_SET_STRING(iovec[j++], core_message);
230 /* Now, let's drop privileges to become the user who owns the
231 * segfaulted process and allocate the coredump memory under
232 * his uid. This also ensures that the credentials journald
233 * will see are the ones of the coredumping user, thus making
234 * sure the user himself gets access to the core dump. */
236 if (setresgid(gid, gid, gid) < 0 ||
237 setresuid(uid, uid, uid) < 0) {
238 log_error("Failed to drop privileges: %m");
243 p = malloc(9 + COREDUMP_MAX);
249 memcpy(p, "COREDUMP=", 9);
251 n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false);
253 log_error("Failed to read core dump data: %s", strerror(-n));
258 iovec[j].iov_base = p;
259 iovec[j].iov_len = 9 + n;
262 r = sd_journal_sendv(iovec, j);
264 log_error("Failed to send coredump: %s", strerror(-r));
272 free(core_timestamp);
280 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;