]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
update TODO
[thirdparty/systemd.git] / src / journal / coredump.c
CommitLineData
f5e04665
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
f5e04665
LP
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
f5e04665 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
f5e04665
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <unistd.h>
803a3464
LP
24#include <stdio.h>
25#include <sys/prctl.h>
f5e04665
LP
26
27#include <systemd/sd-journal.h>
ba1261bc
LP
28
29#ifdef HAVE_LOGIND
f5e04665 30#include <systemd/sd-login.h>
ba1261bc 31#endif
f5e04665
LP
32
33#include "log.h"
34#include "util.h"
b7f7c685 35#include "macro.h"
49e942b2 36#include "mkdir.h"
803a3464 37#include "special.h"
ba1261bc 38#include "cgroup-util.h"
f5e04665 39
41be2ca1 40#define COREDUMP_MAX (768*1024*1024)
f5e04665
LP
41
42enum {
43 ARG_PID = 1,
44 ARG_UID,
45 ARG_GID,
46 ARG_SIGNAL,
47 ARG_TIMESTAMP,
48 ARG_COMM,
49 _ARG_MAX
50};
51
803a3464 52static int divert_coredump(void) {
b7f7c685 53 _cleanup_fclose_ FILE *f = NULL;
803a3464
LP
54
55 log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/.");
56
d2e54fae 57 mkdir_p_label("/var/lib/systemd/coredump", 0755);
803a3464
LP
58
59 f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we");
60 if (!f) {
61 log_error("Failed to create coredump file: %m");
62 return -errno;
63 }
64
65 for (;;) {
66 uint8_t buffer[4096];
67 size_t l, q;
68
69 l = fread(buffer, 1, sizeof(buffer), stdin);
70 if (l <= 0) {
71 if (ferror(f)) {
72 log_error("Failed to read coredump: %m");
b7f7c685 73 return -errno;
803a3464
LP
74 }
75
803a3464
LP
76 break;
77 }
78
79 q = fwrite(buffer, 1, l, f);
80 if (q != l) {
81 log_error("Failed to write coredump: %m");
b7f7c685 82 return -errno;
803a3464
LP
83 }
84 }
85
86 fflush(f);
87
88 if (ferror(f)) {
89 log_error("Failed to write coredump: %m");
b7f7c685 90 return -errno;
803a3464
LP
91 }
92
b7f7c685 93 return 0;
803a3464
LP
94}
95
f5e04665
LP
96int main(int argc, char* argv[]) {
97 int r, j = 0;
5e75606a 98 char *t;
f5e04665
LP
99 ssize_t n;
100 pid_t pid;
fee80f69
LP
101 uid_t uid;
102 gid_t gid;
f5e04665 103 struct iovec iovec[14];
5e75606a 104 char _cleanup_free_ *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
f5e04665 105 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
5e75606a 106 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *p = NULL;
f5e04665 107
803a3464 108 prctl(PR_SET_DUMPABLE, 0);
f5e04665
LP
109
110 if (argc != _ARG_MAX) {
803a3464
LP
111 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
112 log_open();
113
f5e04665
LP
114 log_error("Invalid number of arguments passed from kernel.");
115 r = -EINVAL;
116 goto finish;
117 }
118
119 r = parse_pid(argv[ARG_PID], &pid);
120 if (r < 0) {
803a3464
LP
121 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
122 log_open();
123
f5e04665 124 log_error("Failed to parse PID.");
f5e04665
LP
125 goto finish;
126 }
127
ba1261bc 128 if (cg_pid_get_unit(pid, &t) >= 0) {
803a3464
LP
129
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);
134 log_open();
135
136 r = divert_coredump();
137 goto finish;
138 }
139
140 core_unit = strappend("COREDUMP_UNIT=", t);
b7f7c685 141 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
f9045468 142 core_unit = strappend("COREDUMP_USER_UNIT=", t);
803a3464 143
f9045468
MT
144 if (core_unit)
145 IOVEC_SET_STRING(iovec[j++], core_unit);
146
803a3464
LP
147 /* OK, now we know it's not the journal, hence make use of
148 * it */
149 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
150 log_open();
151
fee80f69
LP
152 r = parse_uid(argv[ARG_UID], &uid);
153 if (r < 0) {
154 log_error("Failed to parse UID.");
f5e04665
LP
155 goto finish;
156 }
157
fee80f69
LP
158 r = parse_gid(argv[ARG_GID], &gid);
159 if (r < 0) {
160 log_error("Failed to parse GID.");
f5e04665
LP
161 goto finish;
162 }
163
f5e04665
LP
164 core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]);
165 if (core_pid)
166 IOVEC_SET_STRING(iovec[j++], core_pid);
167
168 core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]);
169 if (core_uid)
170 IOVEC_SET_STRING(iovec[j++], core_uid);
171
172 core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]);
173 if (core_gid)
174 IOVEC_SET_STRING(iovec[j++], core_gid);
175
176 core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]);
177 if (core_signal)
178 IOVEC_SET_STRING(iovec[j++], core_signal);
179
180 core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]);
181 if (core_comm)
182 IOVEC_SET_STRING(iovec[j++], core_comm);
183
ba1261bc 184#ifdef HAVE_LOGIND
f5e04665
LP
185 if (sd_pid_get_session(pid, &t) >= 0) {
186 core_session = strappend("COREDUMP_SESSION=", t);
187 free(t);
188
189 if (core_session)
190 IOVEC_SET_STRING(iovec[j++], core_session);
191 }
192
ba1261bc
LP
193#endif
194
f5e04665
LP
195 if (get_process_exe(pid, &t) >= 0) {
196 core_exe = strappend("COREDUMP_EXE=", t);
197 free(t);
198
199 if (core_exe)
200 IOVEC_SET_STRING(iovec[j++], core_exe);
201 }
202
9bdbc2e2 203 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
f5e04665
LP
204 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
205 free(t);
206
207 if (core_cmdline)
208 IOVEC_SET_STRING(iovec[j++], core_cmdline);
209 }
210
b7def684 211 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL);
f5e04665
LP
212 if (core_timestamp)
213 IOVEC_SET_STRING(iovec[j++], core_timestamp);
214
215 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
216 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
217
b7def684 218 core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
f5e04665
LP
219 if (core_message)
220 IOVEC_SET_STRING(iovec[j++], core_message);
221
fee80f69
LP
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. */
227
228 if (setresgid(gid, gid, gid) < 0 ||
229 setresuid(uid, uid, uid) < 0) {
230 log_error("Failed to drop privileges: %m");
231 r = -errno;
232 goto finish;
233 }
234
235 p = malloc(9 + COREDUMP_MAX);
236 if (!p) {
0d0f0c50 237 r = log_oom();
fee80f69
LP
238 goto finish;
239 }
240
241 memcpy(p, "COREDUMP=", 9);
242
243 n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false);
244 if (n < 0) {
245 log_error("Failed to read core dump data: %s", strerror(-n));
246 r = (int) n;
247 goto finish;
248 }
249
250 iovec[j].iov_base = p;
251 iovec[j].iov_len = 9 + n;
252 j++;
253
f5e04665
LP
254 r = sd_journal_sendv(iovec, j);
255 if (r < 0)
256 log_error("Failed to send coredump: %s", strerror(-r));
257
258finish:
f5e04665
LP
259 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
260}