]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
Introduce _cleanup_fdset_free_
[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
910003d0
CW
40/* Few programs have less than 3MiB resident */
41#define COREDUMP_MIN_START (3*1024*1024)
c4aa09b0
LP
42/* Make sure to not make this larger than the maximum journal entry
43 * size. See ENTRY_SIZE_MAX in journald-native.c. */
ca0ceb6f 44#define COREDUMP_MAX (767*1024*1024)
f5e04665
LP
45
46enum {
47 ARG_PID = 1,
48 ARG_UID,
49 ARG_GID,
50 ARG_SIGNAL,
51 ARG_TIMESTAMP,
52 ARG_COMM,
53 _ARG_MAX
54};
55
803a3464 56static int divert_coredump(void) {
b7f7c685 57 _cleanup_fclose_ FILE *f = NULL;
803a3464
LP
58
59 log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/.");
60
d2e54fae 61 mkdir_p_label("/var/lib/systemd/coredump", 0755);
803a3464
LP
62
63 f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we");
64 if (!f) {
65 log_error("Failed to create coredump file: %m");
66 return -errno;
67 }
68
69 for (;;) {
70 uint8_t buffer[4096];
71 size_t l, q;
72
73 l = fread(buffer, 1, sizeof(buffer), stdin);
74 if (l <= 0) {
75 if (ferror(f)) {
76 log_error("Failed to read coredump: %m");
b7f7c685 77 return -errno;
803a3464
LP
78 }
79
803a3464
LP
80 break;
81 }
82
83 q = fwrite(buffer, 1, l, f);
84 if (q != l) {
85 log_error("Failed to write coredump: %m");
b7f7c685 86 return -errno;
803a3464
LP
87 }
88 }
89
90 fflush(f);
91
92 if (ferror(f)) {
93 log_error("Failed to write coredump: %m");
b7f7c685 94 return -errno;
803a3464
LP
95 }
96
b7f7c685 97 return 0;
803a3464
LP
98}
99
f5e04665
LP
100int main(int argc, char* argv[]) {
101 int r, j = 0;
5e75606a 102 char *t;
f5e04665
LP
103 ssize_t n;
104 pid_t pid;
fee80f69
LP
105 uid_t uid;
106 gid_t gid;
f5e04665 107 struct iovec iovec[14];
910003d0 108 size_t coredump_bufsize, coredump_size;
7fd1b19b 109 _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
f5e04665 110 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
910003d0 111 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL;
f5e04665 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);
b7f7c685 146 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
f9045468 147 core_unit = strappend("COREDUMP_USER_UNIT=", t);
803a3464 148
f9045468
MT
149 if (core_unit)
150 IOVEC_SET_STRING(iovec[j++], core_unit);
151
803a3464
LP
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
9bdbc2e2 208 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
f5e04665
LP
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
b7def684 216 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL);
f5e04665
LP
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
b7def684 223 core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
f5e04665
LP
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
910003d0
CW
240 coredump_bufsize = COREDUMP_MIN_START;
241 coredump_data = malloc(coredump_bufsize);
242 if (!coredump_data) {
0d0f0c50 243 r = log_oom();
92f2ff44 244 goto finalize;
fee80f69
LP
245 }
246
910003d0
CW
247 memcpy(coredump_data, "COREDUMP=", 9);
248 coredump_size = 9;
fee80f69 249
910003d0
CW
250 for (;;) {
251 n = loop_read(STDIN_FILENO, coredump_data + coredump_size,
252 coredump_bufsize - coredump_size, false);
253 if (n < 0) {
254 log_error("Failed to read core dump data: %s", strerror(-n));
255 r = (int) n;
256 goto finish;
257 } else if (n == 0)
258 break;
259
260 coredump_size += n;
ca0ceb6f
AC
261
262 if(coredump_size > COREDUMP_MAX) {
263 log_error("Coredump too large, ignoring");
92f2ff44 264 goto finalize;
ca0ceb6f
AC
265 }
266
910003d0
CW
267 if (!GREEDY_REALLOC(coredump_data, coredump_bufsize, coredump_size + 1)) {
268 r = log_oom();
92f2ff44 269 goto finalize;
910003d0 270 }
fee80f69
LP
271 }
272
910003d0
CW
273 iovec[j].iov_base = coredump_data;
274 iovec[j].iov_len = coredump_size;
fee80f69
LP
275 j++;
276
92f2ff44 277finalize:
f5e04665
LP
278 r = sd_journal_sendv(iovec, j);
279 if (r < 0)
280 log_error("Failed to send coredump: %s", strerror(-r));
281
282finish:
f5e04665
LP
283 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
284}