]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
util: don't require libcap when building libsystemd-shared
[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"
49e942b2 35#include "mkdir.h"
803a3464 36#include "special.h"
ba1261bc 37#include "cgroup-util.h"
f5e04665 38
de0229ca 39#define COREDUMP_MAX (24*1024*1024)
f5e04665
LP
40
41enum {
42 ARG_PID = 1,
43 ARG_UID,
44 ARG_GID,
45 ARG_SIGNAL,
46 ARG_TIMESTAMP,
47 ARG_COMM,
48 _ARG_MAX
49};
50
803a3464
LP
51static int divert_coredump(void) {
52 FILE *f;
53 int r;
54
55 log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/.");
56
57 mkdir_p("/var/lib/systemd/coredump", 0755);
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");
73 r = -errno;
74 goto finish;
75 }
76
77 r = 0;
78 break;
79 }
80
81 q = fwrite(buffer, 1, l, f);
82 if (q != l) {
83 log_error("Failed to write coredump: %m");
84 r = -errno;
85 goto finish;
86 }
87 }
88
89 fflush(f);
90
91 if (ferror(f)) {
92 log_error("Failed to write coredump: %m");
93 r = -errno;
94 }
95
96finish:
97 fclose(f);
98 return r;
99}
100
f5e04665
LP
101int main(int argc, char* argv[]) {
102 int r, j = 0;
103 char *p = NULL;
104 ssize_t n;
105 pid_t pid;
fee80f69
LP
106 uid_t uid;
107 gid_t gid;
f5e04665
LP
108 struct iovec iovec[14];
109 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, *t;
112
803a3464 113 prctl(PR_SET_DUMPABLE, 0);
f5e04665
LP
114
115 if (argc != _ARG_MAX) {
803a3464
LP
116 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
117 log_open();
118
f5e04665
LP
119 log_error("Invalid number of arguments passed from kernel.");
120 r = -EINVAL;
121 goto finish;
122 }
123
124 r = parse_pid(argv[ARG_PID], &pid);
125 if (r < 0) {
803a3464
LP
126 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
127 log_open();
128
f5e04665 129 log_error("Failed to parse PID.");
f5e04665
LP
130 goto finish;
131 }
132
ba1261bc 133 if (cg_pid_get_unit(pid, &t) >= 0) {
803a3464
LP
134
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);
139 log_open();
140
141 r = divert_coredump();
142 goto finish;
143 }
144
145 core_unit = strappend("COREDUMP_UNIT=", t);
146 free(t);
147
148 if (core_unit)
149 IOVEC_SET_STRING(iovec[j++], core_unit);
150 }
151
152 /* OK, now we know it's not the journal, hence make use of
153 * it */
154 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
155 log_open();
156
fee80f69
LP
157 r = parse_uid(argv[ARG_UID], &uid);
158 if (r < 0) {
159 log_error("Failed to parse UID.");
f5e04665
LP
160 goto finish;
161 }
162
fee80f69
LP
163 r = parse_gid(argv[ARG_GID], &gid);
164 if (r < 0) {
165 log_error("Failed to parse GID.");
f5e04665
LP
166 goto finish;
167 }
168
f5e04665
LP
169 core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]);
170 if (core_pid)
171 IOVEC_SET_STRING(iovec[j++], core_pid);
172
173 core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]);
174 if (core_uid)
175 IOVEC_SET_STRING(iovec[j++], core_uid);
176
177 core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]);
178 if (core_gid)
179 IOVEC_SET_STRING(iovec[j++], core_gid);
180
181 core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]);
182 if (core_signal)
183 IOVEC_SET_STRING(iovec[j++], core_signal);
184
185 core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]);
186 if (core_comm)
187 IOVEC_SET_STRING(iovec[j++], core_comm);
188
ba1261bc 189#ifdef HAVE_LOGIND
f5e04665
LP
190 if (sd_pid_get_session(pid, &t) >= 0) {
191 core_session = strappend("COREDUMP_SESSION=", t);
192 free(t);
193
194 if (core_session)
195 IOVEC_SET_STRING(iovec[j++], core_session);
196 }
197
ba1261bc
LP
198#endif
199
f5e04665
LP
200 if (get_process_exe(pid, &t) >= 0) {
201 core_exe = strappend("COREDUMP_EXE=", t);
202 free(t);
203
204 if (core_exe)
205 IOVEC_SET_STRING(iovec[j++], core_exe);
206 }
207
208 if (get_process_cmdline(pid, LINE_MAX, false, &t) >= 0) {
209 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
210 free(t);
211
212 if (core_cmdline)
213 IOVEC_SET_STRING(iovec[j++], core_cmdline);
214 }
215
216 core_timestamp = join("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL);
217 if (core_timestamp)
218 IOVEC_SET_STRING(iovec[j++], core_timestamp);
219
220 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
221 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
222
223 core_message = join("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
224 if (core_message)
225 IOVEC_SET_STRING(iovec[j++], core_message);
226
fee80f69
LP
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. */
232
233 if (setresgid(gid, gid, gid) < 0 ||
234 setresuid(uid, uid, uid) < 0) {
235 log_error("Failed to drop privileges: %m");
236 r = -errno;
237 goto finish;
238 }
239
240 p = malloc(9 + COREDUMP_MAX);
241 if (!p) {
242 log_error("Out of memory");
243 r = -ENOMEM;
244 goto finish;
245 }
246
247 memcpy(p, "COREDUMP=", 9);
248
249 n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false);
250 if (n < 0) {
251 log_error("Failed to read core dump data: %s", strerror(-n));
252 r = (int) n;
253 goto finish;
254 }
255
256 iovec[j].iov_base = p;
257 iovec[j].iov_len = 9 + n;
258 j++;
259
f5e04665
LP
260 r = sd_journal_sendv(iovec, j);
261 if (r < 0)
262 log_error("Failed to send coredump: %s", strerror(-r));
263
264finish:
265 free(p);
266 free(core_pid);
267 free(core_uid);
268 free(core_gid);
269 free(core_signal);
270 free(core_timestamp);
271 free(core_comm);
272 free(core_exe);
273 free(core_cmdline);
274 free(core_unit);
275 free(core_session);
276 free(core_message);
277
278 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
279}