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 /* Make sure to not make this larger than the maximum journal entry
41 * size. See ENTRY_SIZE_MAX in journald-native.c. */
42 #define COREDUMP_MAX (768*1024*1024)
54 static int divert_coredump(void) {
55 _cleanup_fclose_ FILE *f = NULL;
57 log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/.");
59 mkdir_p_label("/var/lib/systemd/coredump", 0755);
61 f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we");
63 log_error("Failed to create coredump file: %m");
71 l = fread(buffer, 1, sizeof(buffer), stdin);
74 log_error("Failed to read coredump: %m");
81 q = fwrite(buffer, 1, l, f);
83 log_error("Failed to write coredump: %m");
91 log_error("Failed to write coredump: %m");
98 int main(int argc, char* argv[]) {
105 struct iovec iovec[14];
106 char _cleanup_free_ *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
107 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
108 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *p = NULL;
110 prctl(PR_SET_DUMPABLE, 0);
112 if (argc != _ARG_MAX) {
113 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
116 log_error("Invalid number of arguments passed from kernel.");
121 r = parse_pid(argv[ARG_PID], &pid);
123 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
126 log_error("Failed to parse PID.");
130 if (cg_pid_get_unit(pid, &t) >= 0) {
132 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
133 /* Make sure we don't make use of the journal,
134 * if it's the journal which is crashing */
135 log_set_target(LOG_TARGET_KMSG);
138 r = divert_coredump();
142 core_unit = strappend("COREDUMP_UNIT=", t);
143 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
144 core_unit = strappend("COREDUMP_USER_UNIT=", t);
147 IOVEC_SET_STRING(iovec[j++], core_unit);
149 /* OK, now we know it's not the journal, hence make use of
151 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
154 r = parse_uid(argv[ARG_UID], &uid);
156 log_error("Failed to parse UID.");
160 r = parse_gid(argv[ARG_GID], &gid);
162 log_error("Failed to parse GID.");
166 core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]);
168 IOVEC_SET_STRING(iovec[j++], core_pid);
170 core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]);
172 IOVEC_SET_STRING(iovec[j++], core_uid);
174 core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]);
176 IOVEC_SET_STRING(iovec[j++], core_gid);
178 core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]);
180 IOVEC_SET_STRING(iovec[j++], core_signal);
182 core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]);
184 IOVEC_SET_STRING(iovec[j++], core_comm);
187 if (sd_pid_get_session(pid, &t) >= 0) {
188 core_session = strappend("COREDUMP_SESSION=", t);
192 IOVEC_SET_STRING(iovec[j++], core_session);
197 if (get_process_exe(pid, &t) >= 0) {
198 core_exe = strappend("COREDUMP_EXE=", t);
202 IOVEC_SET_STRING(iovec[j++], core_exe);
205 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
206 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
210 IOVEC_SET_STRING(iovec[j++], core_cmdline);
213 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL);
215 IOVEC_SET_STRING(iovec[j++], core_timestamp);
217 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
218 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
220 core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
222 IOVEC_SET_STRING(iovec[j++], core_message);
224 /* Now, let's drop privileges to become the user who owns the
225 * segfaulted process and allocate the coredump memory under
226 * his uid. This also ensures that the credentials journald
227 * will see are the ones of the coredumping user, thus making
228 * sure the user himself gets access to the core dump. */
230 if (setresgid(gid, gid, gid) < 0 ||
231 setresuid(uid, uid, uid) < 0) {
232 log_error("Failed to drop privileges: %m");
237 p = malloc(9 + COREDUMP_MAX);
243 memcpy(p, "COREDUMP=", 9);
245 n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false);
247 log_error("Failed to read core dump data: %s", strerror(-n));
252 iovec[j].iov_base = p;
253 iovec[j].iov_len = 9 + n;
256 r = sd_journal_sendv(iovec, j);
258 log_error("Failed to send coredump: %s", strerror(-r));
261 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;