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 /* Few programs have less than 3MiB resident */
41 #define COREDUMP_MIN_START (3*1024*1024)
42 /* Make sure to not make this larger than the maximum journal entry
43 * size. See ENTRY_SIZE_MAX in journald-native.c. */
44 #define COREDUMP_MAX (768*1024*1024)
56 static int divert_coredump(void) {
57 _cleanup_fclose_ FILE *f = NULL;
59 log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/.");
61 mkdir_p_label("/var/lib/systemd/coredump", 0755);
63 f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we");
65 log_error("Failed to create coredump file: %m");
73 l = fread(buffer, 1, sizeof(buffer), stdin);
76 log_error("Failed to read coredump: %m");
83 q = fwrite(buffer, 1, l, f);
85 log_error("Failed to write coredump: %m");
93 log_error("Failed to write coredump: %m");
100 int main(int argc, char* argv[]) {
107 struct iovec iovec[14];
108 size_t coredump_bufsize, coredump_size;
109 _cleanup_free_ 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, *coredump_data = NULL;
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);
146 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
147 core_unit = strappend("COREDUMP_USER_UNIT=", t);
150 IOVEC_SET_STRING(iovec[j++], core_unit);
152 /* OK, now we know it's not the journal, hence make use of
154 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
157 r = parse_uid(argv[ARG_UID], &uid);
159 log_error("Failed to parse UID.");
163 r = parse_gid(argv[ARG_GID], &gid);
165 log_error("Failed to parse GID.");
169 core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]);
171 IOVEC_SET_STRING(iovec[j++], core_pid);
173 core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]);
175 IOVEC_SET_STRING(iovec[j++], core_uid);
177 core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]);
179 IOVEC_SET_STRING(iovec[j++], core_gid);
181 core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]);
183 IOVEC_SET_STRING(iovec[j++], core_signal);
185 core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]);
187 IOVEC_SET_STRING(iovec[j++], core_comm);
190 if (sd_pid_get_session(pid, &t) >= 0) {
191 core_session = strappend("COREDUMP_SESSION=", t);
195 IOVEC_SET_STRING(iovec[j++], core_session);
200 if (get_process_exe(pid, &t) >= 0) {
201 core_exe = strappend("COREDUMP_EXE=", t);
205 IOVEC_SET_STRING(iovec[j++], core_exe);
208 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
209 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
213 IOVEC_SET_STRING(iovec[j++], core_cmdline);
216 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL);
218 IOVEC_SET_STRING(iovec[j++], core_timestamp);
220 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
221 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
223 core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
225 IOVEC_SET_STRING(iovec[j++], core_message);
227 /* Now, let's drop privileges to become the user who owns the
228 * segfaulted process and allocate the coredump memory under
229 * his uid. This also ensures that the credentials journald
230 * will see are the ones of the coredumping user, thus making
231 * sure the user himself gets access to the core dump. */
233 if (setresgid(gid, gid, gid) < 0 ||
234 setresuid(uid, uid, uid) < 0) {
235 log_error("Failed to drop privileges: %m");
240 coredump_bufsize = COREDUMP_MIN_START;
241 coredump_data = malloc(coredump_bufsize);
242 if (!coredump_data) {
247 memcpy(coredump_data, "COREDUMP=", 9);
251 n = loop_read(STDIN_FILENO, coredump_data + coredump_size,
252 coredump_bufsize - coredump_size, false);
254 log_error("Failed to read core dump data: %s", strerror(-n));
261 if (!GREEDY_REALLOC(coredump_data, coredump_bufsize, coredump_size + 1)) {
267 iovec[j].iov_base = coredump_data;
268 iovec[j].iov_len = coredump_size;
271 r = sd_journal_sendv(iovec, j);
273 log_error("Failed to send coredump: %s", strerror(-r));
276 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;