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>
38 #include "cgroup-util.h"
40 #define COREDUMP_MAX (24*1024*1024)
52 static int divert_coredump(void) {
53 _cleanup_fclose_ FILE *f = NULL;
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");
79 q = fwrite(buffer, 1, l, f);
81 log_error("Failed to write coredump: %m");
89 log_error("Failed to write coredump: %m");
96 int main(int argc, char* argv[]) {
98 _cleanup_free_ char *p = NULL;
103 struct iovec iovec[14];
104 _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
105 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
106 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *t = NULL;
108 prctl(PR_SET_DUMPABLE, 0);
110 if (argc != _ARG_MAX) {
111 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
114 log_error("Invalid number of arguments passed from kernel.");
119 r = parse_pid(argv[ARG_PID], &pid);
121 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
124 log_error("Failed to parse PID.");
128 if (cg_pid_get_unit(pid, &t) >= 0) {
130 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
131 /* Make sure we don't make use of the journal,
132 * if it's the journal which is crashing */
133 log_set_target(LOG_TARGET_KMSG);
136 r = divert_coredump();
140 core_unit = strappend("COREDUMP_UNIT=", t);
141 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
142 core_unit = strappend("COREDUMP_USER_UNIT=", t);
145 IOVEC_SET_STRING(iovec[j++], core_unit);
147 /* OK, now we know it's not the journal, hence make use of
149 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
152 r = parse_uid(argv[ARG_UID], &uid);
154 log_error("Failed to parse UID.");
158 r = parse_gid(argv[ARG_GID], &gid);
160 log_error("Failed to parse GID.");
164 core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]);
166 IOVEC_SET_STRING(iovec[j++], core_pid);
168 core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]);
170 IOVEC_SET_STRING(iovec[j++], core_uid);
172 core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]);
174 IOVEC_SET_STRING(iovec[j++], core_gid);
176 core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]);
178 IOVEC_SET_STRING(iovec[j++], core_signal);
180 core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]);
182 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);
195 if (get_process_exe(pid, &t) >= 0) {
196 core_exe = strappend("COREDUMP_EXE=", t);
200 IOVEC_SET_STRING(iovec[j++], core_exe);
203 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
204 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
208 IOVEC_SET_STRING(iovec[j++], core_cmdline);
211 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL);
213 IOVEC_SET_STRING(iovec[j++], core_timestamp);
215 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
216 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
218 core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
220 IOVEC_SET_STRING(iovec[j++], core_message);
222 /* Now, let's drop privileges to become the user who owns the
223 * segfaulted process and allocate the coredump memory under
224 * his uid. This also ensures that the credentials journald
225 * will see are the ones of the coredumping user, thus making
226 * sure the user himself gets access to the core dump. */
228 if (setresgid(gid, gid, gid) < 0 ||
229 setresuid(uid, uid, uid) < 0) {
230 log_error("Failed to drop privileges: %m");
235 p = malloc(9 + COREDUMP_MAX);
241 memcpy(p, "COREDUMP=", 9);
243 n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false);
245 log_error("Failed to read core dump data: %s", strerror(-n));
250 iovec[j].iov_base = p;
251 iovec[j].iov_len = 9 + n;
254 r = sd_journal_sendv(iovec, j);
256 log_error("Failed to send coredump: %s", strerror(-r));
259 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;