]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
treewide: use log_*_errno whenever %m is in the format string
[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>
34c10968 26#include <sys/types.h>
cacd6403 27#include <sys/xattr.h>
f5e04665 28
4d229b31
UTL
29#ifdef HAVE_ELFUTILS
30# include <dwarf.h>
31# include <elfutils/libdwfl.h>
32#endif
33
73f860db
ZJS
34#include "systemd/sd-journal.h"
35#include "systemd/sd-login.h"
f5e04665
LP
36
37#include "log.h"
38#include "util.h"
3f132692 39#include "fileio.h"
1eef15b1 40#include "strv.h"
b7f7c685 41#include "macro.h"
49e942b2 42#include "mkdir.h"
803a3464 43#include "special.h"
ba1261bc 44#include "cgroup-util.h"
d18d46ec 45#include "journald-native.h"
34c10968
LP
46#include "conf-parser.h"
47#include "copy.h"
8d4e028f 48#include "stacktrace.h"
6388c315 49#include "path-util.h"
cfd652ed 50#include "compress.h"
0dc5d23c 51#include "coredump-vacuum.h"
34c10968
LP
52
53#ifdef HAVE_ACL
34727273
ZJS
54# include <sys/acl.h>
55# include "acl-util.h"
56#endif
57
34c10968
LP
58/* The maximum size up to which we process coredumps */
59#define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
60
61/* The maximum size up to which we leave the coredump around on
62 * disk */
63#define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
64
65/* The maximum size up to which we store the coredump in the
66 * journal */
67#define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
f5e04665 68
c4aa09b0 69/* Make sure to not make this larger than the maximum journal entry
874bc134
ZJS
70 * size. See DATA_SIZE_MAX in journald-native.c. */
71assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
f5e04665
LP
72
73enum {
1eef15b1
ZJS
74 INFO_PID,
75 INFO_UID,
76 INFO_GID,
77 INFO_SIGNAL,
78 INFO_TIMESTAMP,
79 INFO_COMM,
80 INFO_EXE,
81 _INFO_LEN
f5e04665
LP
82};
83
34c10968
LP
84typedef enum CoredumpStorage {
85 COREDUMP_STORAGE_NONE,
86 COREDUMP_STORAGE_EXTERNAL,
87 COREDUMP_STORAGE_JOURNAL,
88 COREDUMP_STORAGE_BOTH,
89 _COREDUMP_STORAGE_MAX,
90 _COREDUMP_STORAGE_INVALID = -1
91} CoredumpStorage;
92
34c10968
LP
93static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
94 [COREDUMP_STORAGE_NONE] = "none",
95 [COREDUMP_STORAGE_EXTERNAL] = "external",
96 [COREDUMP_STORAGE_JOURNAL] = "journal",
97 [COREDUMP_STORAGE_BOTH] = "both",
98};
99
100DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
8c9571d0 101static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
34727273
ZJS
102
103static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
8c9571d0 104static bool arg_compress = true;
34727273
ZJS
105static off_t arg_process_size_max = PROCESS_SIZE_MAX;
106static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
107static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
0dc5d23c
LP
108static off_t arg_keep_free = (off_t) -1;
109static off_t arg_max_use = (off_t) -1;
34c10968
LP
110
111static int parse_config(void) {
34c10968 112 static const ConfigTableItem items[] = {
8c9571d0
LP
113 { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
114 { "Coredump", "Compress", config_parse_bool, 0, &arg_compress },
115 { "Coredump", "ProcessSizeMax", config_parse_iec_off, 0, &arg_process_size_max },
116 { "Coredump", "ExternalSizeMax", config_parse_iec_off, 0, &arg_external_size_max },
117 { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
118 { "Coredump", "KeepFree", config_parse_iec_off, 0, &arg_keep_free },
119 { "Coredump", "MaxUse", config_parse_iec_off, 0, &arg_max_use },
34c10968
LP
120 {}
121 };
122
36f822c4
ZJS
123 return config_parse(NULL, "/etc/systemd/coredump.conf", NULL,
124 "Coredump\0",
125 config_item_table_lookup, items,
126 false, false, true, NULL);
34c10968
LP
127}
128
129static int fix_acl(int fd, uid_t uid) {
130
131#ifdef HAVE_ACL
132 _cleanup_(acl_freep) acl_t acl = NULL;
133 acl_entry_t entry;
134 acl_permset_t permset;
135
b59233e6
LP
136 assert(fd >= 0);
137
34c10968
LP
138 if (uid <= SYSTEM_UID_MAX)
139 return 0;
140
141 /* Make sure normal users can read (but not write or delete)
142 * their own coredumps */
143
144 acl = acl_get_fd(fd);
145 if (!acl) {
56f64d95 146 log_error_errno(errno, "Failed to get ACL: %m");
34c10968
LP
147 return -errno;
148 }
149
150 if (acl_create_entry(&acl, &entry) < 0 ||
151 acl_set_tag_type(entry, ACL_USER) < 0 ||
152 acl_set_qualifier(entry, &uid) < 0) {
56f64d95 153 log_error_errno(errno, "Failed to patch ACL: %m");
34c10968
LP
154 return -errno;
155 }
156
157 if (acl_get_permset(entry, &permset) < 0 ||
158 acl_add_perm(permset, ACL_READ) < 0 ||
159 calc_acl_mask_if_needed(&acl) < 0) {
56f64d95 160 log_warning_errno(errno, "Failed to patch ACL: %m");
34c10968
LP
161 return -errno;
162 }
163
164 if (acl_set_fd(fd, acl) < 0) {
56f64d95 165 log_error_errno(errno, "Failed to apply ACL: %m");
34c10968
LP
166 return -errno;
167 }
168#endif
169
170 return 0;
171}
172
1eef15b1 173static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
0cd77f97 174
1eef15b1
ZJS
175 static const char * const xattrs[_INFO_LEN] = {
176 [INFO_PID] = "user.coredump.pid",
177 [INFO_UID] = "user.coredump.uid",
178 [INFO_GID] = "user.coredump.gid",
179 [INFO_SIGNAL] = "user.coredump.signal",
180 [INFO_TIMESTAMP] = "user.coredump.timestamp",
181 [INFO_COMM] = "user.coredump.comm",
182 [INFO_EXE] = "user.coredump.exe",
0cd77f97
LP
183 };
184
34c10968 185 int r = 0;
0cd77f97 186 unsigned i;
34c10968 187
b59233e6
LP
188 assert(fd >= 0);
189
1eef15b1 190 /* Attach some metadata to coredumps via extended
34c10968
LP
191 * attributes. Just because we can. */
192
1eef15b1
ZJS
193 for (i = 0; i < _INFO_LEN; i++) {
194 int k;
195
196 if (isempty(info[i]) || !xattrs[i])
0cd77f97 197 continue;
34c10968 198
1eef15b1
ZJS
199 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
200 if (k < 0 && r == 0)
34c10968 201 r = -errno;
0cd77f97 202 }
34c10968
LP
203
204 return r;
205}
206
b0b21dce 207#define filename_escape(s) xescape((s), "./ ")
34c10968 208
b59233e6
LP
209static int fix_permissions(
210 int fd,
211 const char *filename,
212 const char *target,
213 const char *info[_INFO_LEN],
214 uid_t uid) {
215
216 assert(fd >= 0);
217 assert(filename);
218 assert(target);
219 assert(info);
cfd652ed
ZJS
220
221 /* Ignore errors on these */
222 fchmod(fd, 0640);
223 fix_acl(fd, uid);
224 fix_xattr(fd, info);
225
226 if (fsync(fd) < 0) {
56f64d95 227 log_error_errno(errno, "Failed to sync coredump %s: %m", filename);
cfd652ed
ZJS
228 return -errno;
229 }
230
231 if (rename(filename, target) < 0) {
56f64d95 232 log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
cfd652ed
ZJS
233 return -errno;
234 }
235
236 return 0;
237}
238
239static int maybe_remove_external_coredump(const char *filename, off_t size) {
240
b59233e6 241 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
cfd652ed
ZJS
242
243 if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
244 size <= arg_external_size_max)
245 return 0;
246
247 if (!filename)
248 return 1;
249
9d951bf4 250 if (unlink(filename) < 0 && errno != ENOENT) {
56f64d95 251 log_error_errno(errno, "Failed to unlink %s: %m", filename);
cfd652ed
ZJS
252 return -errno;
253 }
254
255 return 1;
256}
257
b59233e6
LP
258static int make_filename(const char *info[_INFO_LEN], char **ret) {
259 _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
34c10968 260 sd_id128_t boot;
34c10968
LP
261 int r;
262
1eef15b1 263 assert(info);
34c10968 264
1eef15b1 265 c = filename_escape(info[INFO_COMM]);
34c10968 266 if (!c)
b59233e6 267 return -ENOMEM;
34c10968 268
0dc5d23c
LP
269 u = filename_escape(info[INFO_UID]);
270 if (!u)
b59233e6 271 return -ENOMEM;
34c10968
LP
272
273 r = sd_id128_get_boot(&boot);
b59233e6 274 if (r < 0)
34c10968 275 return r;
34c10968 276
b59233e6
LP
277 p = filename_escape(info[INFO_PID]);
278 if (!p)
279 return -ENOMEM;
280
281 t = filename_escape(info[INFO_TIMESTAMP]);
282 if (!t)
283 return -ENOMEM;
284
285 if (asprintf(ret,
0dc5d23c 286 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
34c10968 287 c,
0dc5d23c 288 u,
34c10968
LP
289 SD_ID128_FORMAT_VAL(boot),
290 p,
b59233e6
LP
291 t) < 0)
292 return -ENOMEM;
293
294 return 0;
295}
296
297static int save_external_coredump(
298 const char *info[_INFO_LEN],
299 uid_t uid,
300 char **ret_filename,
301 int *ret_fd,
302 off_t *ret_size) {
303
304 _cleanup_free_ char *fn = NULL, *tmp = NULL;
305 _cleanup_close_ int fd = -1;
306 struct stat st;
307 int r;
308
309 assert(info);
310 assert(ret_filename);
311 assert(ret_fd);
312 assert(ret_size);
313
314 r = make_filename(info, &fn);
23bbb0de
MS
315 if (r < 0)
316 return log_error_errno(r, "Failed to determine coredump file name: %m");
34c10968
LP
317
318 tmp = tempfn_random(fn);
319 if (!tmp)
320 return log_oom();
803a3464 321
d2e54fae 322 mkdir_p_label("/var/lib/systemd/coredump", 0755);
803a3464 323
34c10968
LP
324 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
325 if (fd < 0) {
56f64d95 326 log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
803a3464
LP
327 return -errno;
328 }
329
93240d3a 330 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
84ee0960 331 if (r == -EFBIG) {
0dc5d23c 332 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
333 goto fail;
334 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
0dc5d23c 335 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
336 goto fail;
337 } else if (r < 0) {
da927ba9 338 log_error_errno(r, "Failed to dump coredump to file: %m");
34c10968
LP
339 goto fail;
340 }
803a3464 341
34c10968 342 if (fstat(fd, &st) < 0) {
56f64d95 343 log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
34c10968
LP
344 goto fail;
345 }
346
7849c2ac 347 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
56f64d95 348 log_error_errno(errno, "Failed to seek on %s: %m", tmp);
b59233e6 349 goto fail;
7849c2ac
TA
350 }
351
d89c8fdf 352#if defined(HAVE_XZ) || defined(HAVE_LZ4)
cfd652ed 353 /* If we will remove the coredump anyway, do not compress. */
34727273 354 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
8c9571d0 355 && arg_compress) {
cfd652ed 356
b59233e6
LP
357 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
358 _cleanup_close_ int fd_compressed = -1;
cfd652ed 359
d89c8fdf 360 fn_compressed = strappend(fn, COMPRESSED_EXT);
b59233e6 361 if (!fn_compressed) {
d89c8fdf 362 log_oom();
cfd652ed
ZJS
363 goto uncompressed;
364 }
365
b59233e6
LP
366 tmp_compressed = tempfn_random(fn_compressed);
367 if (!tmp_compressed) {
d89c8fdf 368 log_oom();
b59233e6 369 goto uncompressed;
cfd652ed
ZJS
370 }
371
b59233e6
LP
372 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
373 if (fd_compressed < 0) {
56f64d95 374 log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
b59233e6 375 goto uncompressed;
cfd652ed
ZJS
376 }
377
d89c8fdf 378 r = compress_stream(fd, fd_compressed, -1);
b59233e6 379 if (r < 0) {
da927ba9 380 log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
b59233e6
LP
381 goto fail_compressed;
382 }
383
384 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
cfd652ed 385 if (r < 0)
b59233e6
LP
386 goto fail_compressed;
387
388 /* OK, this worked, we can get rid of the uncompressed version now */
389 unlink_noerrno(tmp);
cfd652ed 390
b59233e6
LP
391 *ret_filename = fn_compressed; /* compressed */
392 *ret_fd = fd; /* uncompressed */
393 *ret_size = st.st_size; /* uncompressed */
cfd652ed 394
b59233e6 395 fn_compressed = NULL;
cfd652ed
ZJS
396 fd = -1;
397
398 return 0;
399
b59233e6
LP
400 fail_compressed:
401 unlink_noerrno(tmp_compressed);
34c10968 402 }
cfd652ed
ZJS
403
404uncompressed:
3b1a55e1 405#endif
cfd652ed
ZJS
406 r = fix_permissions(fd, tmp, fn, info, uid);
407 if (r < 0)
408 goto fail;
34c10968
LP
409
410 *ret_filename = fn;
411 *ret_fd = fd;
412 *ret_size = st.st_size;
413
414 fn = NULL;
415 fd = -1;
416
417 return 0;
418
419fail:
420 unlink_noerrno(tmp);
421 return r;
422}
423
424static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
425 _cleanup_free_ char *field = NULL;
426 ssize_t n;
427
8d4e028f 428 assert(fd >= 0);
34c10968
LP
429 assert(ret);
430 assert(ret_size);
431
432 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
56f64d95 433 log_warning_errno(errno, "Failed to seek: %m");
34c10968 434 return -errno;
803a3464
LP
435 }
436
34c10968
LP
437 field = malloc(9 + size);
438 if (!field) {
cfd652ed 439 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
34c10968
LP
440 return -ENOMEM;
441 }
442
443 memcpy(field, "COREDUMP=", 9);
444
445 n = read(fd, field + 9, size);
23bbb0de
MS
446 if (n < 0)
447 return log_error_errno((int) n, "Failed to read core data: %m");
34c10968
LP
448 if ((size_t) n < size) {
449 log_error("Core data too short.");
450 return -EIO;
451 }
452
453 *ret = field;
454 *ret_size = size + 9;
455
456 field = NULL;
457
458 return 0;
459}
803a3464 460
3f132692
JF
461/* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
462 * 0:/dev/pts/23
463 * pos: 0
464 * flags: 0100002
465 *
466 * 1:/dev/pts/23
467 * pos: 0
468 * flags: 0100002
469 *
470 * 2:/dev/pts/23
471 * pos: 0
472 * flags: 0100002
473 * EOF
474 */
475static int compose_open_fds(pid_t pid, char **open_fds) {
476 _cleanup_fclose_ FILE *stream = NULL;
3f132692 477 size_t ignored_size;
59059b4a 478 const char *fddelim = "", *path;
3f132692
JF
479 struct dirent *dent = NULL;
480 _cleanup_closedir_ DIR *proc_fd_dir = NULL;
59059b4a 481 _cleanup_close_ int proc_fdinfo_fd = -1;
3f132692
JF
482 int r = 0;
483
484 assert(pid >= 0);
485 assert(open_fds != NULL);
486
59059b4a 487 path = procfs_file_alloca(pid, "fd");
3f132692 488 proc_fd_dir = opendir(path);
59059b4a
ZJS
489 if (!proc_fd_dir)
490 return -errno;
3f132692 491
59059b4a
ZJS
492 proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo",
493 O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
494 if (proc_fdinfo_fd < 0)
495 return -errno;
3f132692
JF
496
497 stream = open_memstream(open_fds, &ignored_size);
498 if (!stream)
499 return -ENOMEM;
500
501 for (dent = readdir(proc_fd_dir); dent != NULL; dent = readdir(proc_fd_dir)) {
502 _cleanup_free_ char *fdname = NULL;
59059b4a 503 int fd;
3f132692 504 _cleanup_fclose_ FILE *fdinfo = NULL;
59059b4a 505 char line[LINE_MAX];
3f132692
JF
506
507 if (dent->d_name[0] == '.' || strcmp(dent->d_name, "..") == 0)
508 continue;
509
59059b4a 510 r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname);
3f132692
JF
511 if (r < 0)
512 return r;
513
514 fprintf(stream, "%s%s:%s\n", fddelim, dent->d_name, fdname);
515 fddelim = "\n";
516
517 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
59059b4a
ZJS
518 fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
519 if (fd < 0)
3f132692
JF
520 continue;
521
59059b4a
ZJS
522 fdinfo = fdopen(fd, "re");
523 if (fdinfo == NULL) {
524 close(fd);
3f132692 525 continue;
59059b4a 526 }
3f132692
JF
527
528 while(fgets(line, sizeof(line), fdinfo) != NULL)
529 fprintf(stream, "%s%s",
530 line, strchr(line, '\n') == NULL ? "\n" : "");
531 }
532
533 return 0;
534}
535
f5e04665 536int main(int argc, char* argv[]) {
34c10968
LP
537
538 _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
539 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
540 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
3f132692
JF
541 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL, *core_open_fds = NULL,
542 *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL,
543 *core_cwd = NULL, *core_root = NULL, *core_environ = NULL,
9fe13294 544 *exe = NULL, *comm = NULL, *filename = NULL;
1eef15b1 545 const char *info[_INFO_LEN];
34c10968
LP
546
547 _cleanup_close_ int coredump_fd = -1;
548
3f132692 549 struct iovec iovec[26];
34c10968 550 off_t coredump_size;
f5e04665 551 int r, j = 0;
a035f819 552 uid_t uid, owner_uid;
fee80f69 553 gid_t gid;
a035f819 554 pid_t pid;
34c10968 555 char *t;
3f132692 556 const char *p;
f5e04665 557
34c10968 558 /* Make sure we never enter a loop */
803a3464 559 prctl(PR_SET_DUMPABLE, 0);
f5e04665 560
34c10968
LP
561 /* First, log to a safe place, since we don't know what
562 * crashed and it might be journald which we'd rather not log
563 * to then. */
564 log_set_target(LOG_TARGET_KMSG);
34c10968 565 log_open();
803a3464 566
1eef15b1
ZJS
567 if (argc < INFO_COMM + 1) {
568 log_error("Not enough arguments passed from kernel (%d, expected %d).",
569 argc - 1, INFO_COMM + 1 - 1);
f5e04665
LP
570 r = -EINVAL;
571 goto finish;
572 }
573
34c10968
LP
574 /* Ignore all parse errors */
575 parse_config();
8c9571d0
LP
576
577 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
578 log_debug("Selected compression %s.", yes_no(arg_compress));
34c10968 579
1eef15b1 580 r = parse_uid(argv[INFO_UID + 1], &uid);
f5e04665 581 if (r < 0) {
34c10968
LP
582 log_error("Failed to parse UID.");
583 goto finish;
584 }
803a3464 585
1eef15b1 586 r = parse_pid(argv[INFO_PID + 1], &pid);
34c10968 587 if (r < 0) {
f5e04665 588 log_error("Failed to parse PID.");
f5e04665
LP
589 goto finish;
590 }
591
1eef15b1 592 r = parse_gid(argv[INFO_GID + 1], &gid);
34c10968
LP
593 if (r < 0) {
594 log_error("Failed to parse GID.");
595 goto finish;
596 }
597
1eef15b1 598 if (get_process_comm(pid, &comm) < 0) {
3f85ef0f 599 log_warning("Failed to get COMM, falling back to the command line.");
1eef15b1
ZJS
600 comm = strv_join(argv + INFO_COMM + 1, " ");
601 }
602
603 if (get_process_exe(pid, &exe) < 0)
604 log_warning("Failed to get EXE.");
605
606 info[INFO_PID] = argv[INFO_PID + 1];
607 info[INFO_UID] = argv[INFO_UID + 1];
608 info[INFO_GID] = argv[INFO_GID + 1];
609 info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
610 info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
611 info[INFO_COMM] = comm;
612 info[INFO_EXE] = exe;
613
ba1261bc 614 if (cg_pid_get_unit(pid, &t) >= 0) {
803a3464
LP
615
616 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
803a3464 617
34c10968
LP
618 /* If we are journald, we cut things short,
619 * don't write to the journal, but still
620 * create a coredump. */
621
622 if (arg_storage != COREDUMP_STORAGE_NONE)
623 arg_storage = COREDUMP_STORAGE_EXTERNAL;
624
9fe13294 625 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968
LP
626 if (r < 0)
627 goto finish;
628
9fe13294 629 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
630 if (r < 0)
631 goto finish;
632
9fe13294 633 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
803a3464
LP
634 goto finish;
635 }
636
637 core_unit = strappend("COREDUMP_UNIT=", t);
b7f7c685 638 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
f9045468 639 core_unit = strappend("COREDUMP_USER_UNIT=", t);
803a3464 640
f9045468
MT
641 if (core_unit)
642 IOVEC_SET_STRING(iovec[j++], core_unit);
643
34c10968
LP
644 /* OK, now we know it's not the journal, hence we can make use
645 * of it now. */
803a3464
LP
646 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
647 log_open();
648
1eef15b1 649 core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
f5e04665
LP
650 if (core_pid)
651 IOVEC_SET_STRING(iovec[j++], core_pid);
652
1eef15b1 653 core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
f5e04665
LP
654 if (core_uid)
655 IOVEC_SET_STRING(iovec[j++], core_uid);
656
1eef15b1 657 core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
f5e04665
LP
658 if (core_gid)
659 IOVEC_SET_STRING(iovec[j++], core_gid);
660
1eef15b1 661 core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
f5e04665
LP
662 if (core_signal)
663 IOVEC_SET_STRING(iovec[j++], core_signal);
664
f5e04665
LP
665 if (sd_pid_get_session(pid, &t) >= 0) {
666 core_session = strappend("COREDUMP_SESSION=", t);
667 free(t);
668
669 if (core_session)
670 IOVEC_SET_STRING(iovec[j++], core_session);
671 }
672
a035f819 673 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
7de80bfe
KZ
674 r = asprintf(&core_owner_uid,
675 "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
676 if (r > 0)
a035f819
LP
677 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
678 }
679
680 if (sd_pid_get_slice(pid, &t) >= 0) {
681 core_slice = strappend("COREDUMP_SLICE=", t);
682 free(t);
683
684 if (core_slice)
685 IOVEC_SET_STRING(iovec[j++], core_slice);
686 }
687
1eef15b1
ZJS
688 if (comm) {
689 core_comm = strappend("COREDUMP_COMM=", comm);
690 if (core_comm)
691 IOVEC_SET_STRING(iovec[j++], core_comm);
692 }
693
694 if (exe) {
8d4e028f 695 core_exe = strappend("COREDUMP_EXE=", exe);
f5e04665
LP
696 if (core_exe)
697 IOVEC_SET_STRING(iovec[j++], core_exe);
698 }
699
9bdbc2e2 700 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
f5e04665
LP
701 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
702 free(t);
703
704 if (core_cmdline)
705 IOVEC_SET_STRING(iovec[j++], core_cmdline);
706 }
707
a035f819
LP
708 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
709 core_cgroup = strappend("COREDUMP_CGROUP=", t);
710 free(t);
711
712 if (core_cgroup)
713 IOVEC_SET_STRING(iovec[j++], core_cgroup);
714 }
715
3f132692
JF
716 if (compose_open_fds(pid, &t) >= 0) {
717 core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
718 free(t);
719
720 if (core_open_fds)
721 IOVEC_SET_STRING(iovec[j++], core_open_fds);
722 }
723
724 p = procfs_file_alloca(pid, "status");
725 if (read_full_file(p, &t, NULL) >= 0) {
726 core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
727 free(t);
728
729 if (core_proc_status)
730 IOVEC_SET_STRING(iovec[j++], core_proc_status);
731 }
732
733 p = procfs_file_alloca(pid, "maps");
734 if (read_full_file(p, &t, NULL) >= 0) {
735 core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
736 free(t);
737
738 if (core_proc_maps)
739 IOVEC_SET_STRING(iovec[j++], core_proc_maps);
740 }
741
742 p = procfs_file_alloca(pid, "limits");
743 if (read_full_file(p, &t, NULL) >= 0) {
744 core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
745 free(t);
746
747 if (core_proc_limits)
748 IOVEC_SET_STRING(iovec[j++], core_proc_limits);
749 }
750
751 p = procfs_file_alloca(pid, "cgroup");
752 if (read_full_file(p, &t, NULL) >=0) {
753 core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
754 free(t);
755
756 if (core_proc_cgroup)
757 IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
758 }
759
760 if (get_process_cwd(pid, &t) >= 0) {
761 core_cwd = strappend("COREDUMP_CWD=", t);
762 free(t);
763
764 if (core_cwd)
765 IOVEC_SET_STRING(iovec[j++], core_cwd);
766 }
767
768 if (get_process_root(pid, &t) >= 0) {
769 core_root = strappend("COREDUMP_ROOT=", t);
770 free(t);
771
772 if (core_root)
773 IOVEC_SET_STRING(iovec[j++], core_root);
774 }
775
776 if (get_process_environ(pid, &t) >= 0) {
777 core_environ = strappend("COREDUMP_ENVIRON=", t);
778 free(t);
779
780 if (core_environ)
781 IOVEC_SET_STRING(iovec[j++], core_environ);
782 }
783
1eef15b1 784 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
f5e04665
LP
785 if (core_timestamp)
786 IOVEC_SET_STRING(iovec[j++], core_timestamp);
787
788 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
789 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
790
0dc5d23c
LP
791 /* Vacuum before we write anything again */
792 coredump_vacuum(-1, arg_keep_free, arg_max_use);
793
34c10968 794 /* Always stream the coredump to disk, if that's possible */
9fe13294 795 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968 796 if (r < 0)
2424a475
ZJS
797 /* skip whole core dumping part */
798 goto log;
34c10968
LP
799
800 /* If we don't want to keep the coredump on disk, remove it
8d4e028f
LP
801 * now, as later on we will lack the privileges for
802 * it. However, we keep the fd to it, so that we can still
803 * process it and log it. */
9fe13294 804 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
805 if (r < 0)
806 goto finish;
9fe13294
ZJS
807 if (r == 0) {
808 const char *coredump_filename;
809
810 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
811 IOVEC_SET_STRING(iovec[j++], coredump_filename);
812 }
34c10968 813
0dc5d23c
LP
814 /* Vacuum again, but exclude the coredump we just created */
815 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
816
fee80f69
LP
817 /* Now, let's drop privileges to become the user who owns the
818 * segfaulted process and allocate the coredump memory under
b26c631a
KP
819 * the user's uid. This also ensures that the credentials
820 * journald will see are the ones of the coredumping user,
821 * thus making sure the user gets access to the core dump. */
fee80f69
LP
822 if (setresgid(gid, gid, gid) < 0 ||
823 setresuid(uid, uid, uid) < 0) {
56f64d95 824 log_error_errno(errno, "Failed to drop privileges: %m");
fee80f69
LP
825 r = -errno;
826 goto finish;
827 }
828
8d4e028f
LP
829#ifdef HAVE_ELFUTILS
830 /* Try to get a strack trace if we can */
831 if (coredump_size <= arg_process_size_max) {
832 _cleanup_free_ char *stacktrace = NULL;
833
834 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
835 if (r >= 0)
1eef15b1 836 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
4d229b31
UTL
837 else if (r == -EINVAL)
838 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
8d4e028f 839 else
da927ba9 840 log_warning_errno(r, "Failed to generate stack trace: %m");
8d4e028f
LP
841 }
842
843 if (!core_message)
844#endif
2424a475 845log:
1eef15b1 846 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
8d4e028f
LP
847 if (core_message)
848 IOVEC_SET_STRING(iovec[j++], core_message);
849
34c10968
LP
850 /* Optionally store the entire coredump in the journal */
851 if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
852 coredump_size <= (off_t) arg_journal_size_max) {
853 size_t sz;
fee80f69 854
34c10968 855 /* Store the coredump itself in the journal */
fee80f69 856
34c10968
LP
857 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
858 if (r >= 0) {
859 iovec[j].iov_base = coredump_data;
860 iovec[j].iov_len = sz;
861 j++;
ca0ceb6f 862 }
fee80f69
LP
863 }
864
f5e04665
LP
865 r = sd_journal_sendv(iovec, j);
866 if (r < 0)
da927ba9 867 log_error_errno(r, "Failed to log coredump: %m");
f5e04665
LP
868
869finish:
f5e04665
LP
870 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
871}