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