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"
39 #include "journald-native.h"
41 /* Few programs have less than 3MiB resident */
42 #define COREDUMP_MIN_START (3*1024*1024u)
43 /* Make sure to not make this larger than the maximum journal entry
44 * size. See ENTRY_SIZE_MAX in journald-native.c. */
45 #define COREDUMP_MAX (767*1024*1024u)
46 assert_cc(COREDUMP_MAX <= ENTRY_SIZE_MAX);
58 static int divert_coredump(void) {
59 _cleanup_fclose_ FILE *f = NULL;
61 log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/.");
63 mkdir_p_label("/var/lib/systemd/coredump", 0755);
65 f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we");
67 log_error("Failed to create coredump file: %m");
75 l = fread(buffer, 1, sizeof(buffer), stdin);
78 log_error("Failed to read coredump: %m");
85 q = fwrite(buffer, 1, l, f);
87 log_error("Failed to write coredump: %m");
95 log_error("Failed to write coredump: %m");
102 int main(int argc, char* argv[]) {
109 struct iovec iovec[14];
110 size_t coredump_bufsize = 0, coredump_size = 0;
111 _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
112 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
113 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL;
115 prctl(PR_SET_DUMPABLE, 0);
117 if (argc != _ARG_MAX) {
118 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
121 log_error("Invalid number of arguments passed from kernel.");
126 r = parse_pid(argv[ARG_PID], &pid);
128 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
131 log_error("Failed to parse PID.");
135 if (cg_pid_get_unit(pid, &t) >= 0) {
137 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
138 /* Make sure we don't make use of the journal,
139 * if it's the journal which is crashing */
140 log_set_target(LOG_TARGET_KMSG);
143 r = divert_coredump();
147 core_unit = strappend("COREDUMP_UNIT=", t);
148 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
149 core_unit = strappend("COREDUMP_USER_UNIT=", t);
152 IOVEC_SET_STRING(iovec[j++], core_unit);
154 /* OK, now we know it's not the journal, hence make use of
156 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
159 r = parse_uid(argv[ARG_UID], &uid);
161 log_error("Failed to parse UID.");
165 r = parse_gid(argv[ARG_GID], &gid);
167 log_error("Failed to parse GID.");
171 core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]);
173 IOVEC_SET_STRING(iovec[j++], core_pid);
175 core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]);
177 IOVEC_SET_STRING(iovec[j++], core_uid);
179 core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]);
181 IOVEC_SET_STRING(iovec[j++], core_gid);
183 core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]);
185 IOVEC_SET_STRING(iovec[j++], core_signal);
187 core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]);
189 IOVEC_SET_STRING(iovec[j++], core_comm);
192 if (sd_pid_get_session(pid, &t) >= 0) {
193 core_session = strappend("COREDUMP_SESSION=", t);
197 IOVEC_SET_STRING(iovec[j++], core_session);
202 if (get_process_exe(pid, &t) >= 0) {
203 core_exe = strappend("COREDUMP_EXE=", t);
207 IOVEC_SET_STRING(iovec[j++], core_exe);
210 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
211 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
215 IOVEC_SET_STRING(iovec[j++], core_cmdline);
218 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL);
220 IOVEC_SET_STRING(iovec[j++], core_timestamp);
222 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
223 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
225 core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
227 IOVEC_SET_STRING(iovec[j++], core_message);
229 /* Now, let's drop privileges to become the user who owns the
230 * segfaulted process and allocate the coredump memory under
231 * his uid. This also ensures that the credentials journald
232 * will see are the ones of the coredumping user, thus making
233 * sure the user himself gets access to the core dump. */
235 if (setresgid(gid, gid, gid) < 0 ||
236 setresuid(uid, uid, uid) < 0) {
237 log_error("Failed to drop privileges: %m");
243 if (!GREEDY_REALLOC(coredump_data, coredump_bufsize,
244 MAX(coredump_size + 1, COREDUMP_MIN_START/2))) {
245 log_warning("Failed to allocate memory for core, core will not be stored.");
249 if (coredump_size == 0) {
250 memcpy(coredump_data, "COREDUMP=", 9);
254 n = loop_read(STDIN_FILENO, coredump_data + coredump_size,
255 coredump_bufsize - coredump_size, false);
257 log_error("Failed to read core data: %s", strerror(-n));
265 if (coredump_size > COREDUMP_MAX) {
266 log_error("Core too large, core will not be stored.");
271 iovec[j].iov_base = coredump_data;
272 iovec[j].iov_len = coredump_size;
276 r = sd_journal_sendv(iovec, j);
278 log_error("Failed to log coredump: %s", strerror(-r));
281 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;