]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
journalctl: print all possible lines immediately with --follow + --since
[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) {
146 log_error("Failed to get ACL: %m");
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) {
153 log_error("Failed to patch ACL: %m");
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) {
160 log_warning("Failed to patch ACL: %m");
161 return -errno;
162 }
163
164 if (acl_set_fd(fd, acl) < 0) {
165 log_error("Failed to apply ACL: %m");
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) {
227 log_error("Failed to sync coredump %s: %m", filename);
228 return -errno;
229 }
230
231 if (rename(filename, target) < 0) {
232 log_error("Failed to rename coredump %s -> %s: %m", filename, target);
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) {
cfd652ed
ZJS
251 log_error("Failed to unlink %s: %m", filename);
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);
315 if (r < 0) {
316 log_error("Failed to determine coredump file name: %s", strerror(-r));
317 return r;
318 }
34c10968
LP
319
320 tmp = tempfn_random(fn);
321 if (!tmp)
322 return log_oom();
803a3464 323
d2e54fae 324 mkdir_p_label("/var/lib/systemd/coredump", 0755);
803a3464 325
34c10968
LP
326 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
327 if (fd < 0) {
cfd652ed 328 log_error("Failed to create coredump file %s: %m", tmp);
803a3464
LP
329 return -errno;
330 }
331
93240d3a 332 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
84ee0960 333 if (r == -EFBIG) {
0dc5d23c 334 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
335 goto fail;
336 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
0dc5d23c 337 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
93240d3a
LP
338 goto fail;
339 } else if (r < 0) {
34c10968
LP
340 log_error("Failed to dump coredump to file: %s", strerror(-r));
341 goto fail;
342 }
803a3464 343
34c10968 344 if (fstat(fd, &st) < 0) {
1eef15b1 345 log_error("Failed to fstat coredump %s: %m", tmp);
34c10968
LP
346 goto fail;
347 }
348
7849c2ac
TA
349 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
350 log_error("Failed to seek on %s: %m", tmp);
b59233e6 351 goto fail;
7849c2ac
TA
352 }
353
d89c8fdf 354#if defined(HAVE_XZ) || defined(HAVE_LZ4)
cfd652ed 355 /* If we will remove the coredump anyway, do not compress. */
34727273 356 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
8c9571d0 357 && arg_compress) {
cfd652ed 358
b59233e6
LP
359 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
360 _cleanup_close_ int fd_compressed = -1;
cfd652ed 361
d89c8fdf 362 fn_compressed = strappend(fn, COMPRESSED_EXT);
b59233e6 363 if (!fn_compressed) {
d89c8fdf 364 log_oom();
cfd652ed
ZJS
365 goto uncompressed;
366 }
367
b59233e6
LP
368 tmp_compressed = tempfn_random(fn_compressed);
369 if (!tmp_compressed) {
d89c8fdf 370 log_oom();
b59233e6 371 goto uncompressed;
cfd652ed
ZJS
372 }
373
b59233e6
LP
374 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
375 if (fd_compressed < 0) {
376 log_error("Failed to create file %s: %m", tmp_compressed);
377 goto uncompressed;
cfd652ed
ZJS
378 }
379
d89c8fdf 380 r = compress_stream(fd, fd_compressed, -1);
b59233e6
LP
381 if (r < 0) {
382 log_error("Failed to compress %s: %s", tmp_compressed, strerror(-r));
383 goto fail_compressed;
384 }
385
386 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
cfd652ed 387 if (r < 0)
b59233e6
LP
388 goto fail_compressed;
389
390 /* OK, this worked, we can get rid of the uncompressed version now */
391 unlink_noerrno(tmp);
cfd652ed 392
b59233e6
LP
393 *ret_filename = fn_compressed; /* compressed */
394 *ret_fd = fd; /* uncompressed */
395 *ret_size = st.st_size; /* uncompressed */
cfd652ed 396
b59233e6 397 fn_compressed = NULL;
cfd652ed
ZJS
398 fd = -1;
399
400 return 0;
401
b59233e6
LP
402 fail_compressed:
403 unlink_noerrno(tmp_compressed);
34c10968 404 }
cfd652ed
ZJS
405
406uncompressed:
3b1a55e1 407#endif
cfd652ed
ZJS
408 r = fix_permissions(fd, tmp, fn, info, uid);
409 if (r < 0)
410 goto fail;
34c10968
LP
411
412 *ret_filename = fn;
413 *ret_fd = fd;
414 *ret_size = st.st_size;
415
416 fn = NULL;
417 fd = -1;
418
419 return 0;
420
421fail:
422 unlink_noerrno(tmp);
423 return r;
424}
425
426static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
427 _cleanup_free_ char *field = NULL;
428 ssize_t n;
429
8d4e028f 430 assert(fd >= 0);
34c10968
LP
431 assert(ret);
432 assert(ret_size);
433
434 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
435 log_warning("Failed to seek: %m");
436 return -errno;
803a3464
LP
437 }
438
34c10968
LP
439 field = malloc(9 + size);
440 if (!field) {
cfd652ed 441 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
34c10968
LP
442 return -ENOMEM;
443 }
444
445 memcpy(field, "COREDUMP=", 9);
446
447 n = read(fd, field + 9, size);
448 if (n < 0) {
449 log_error("Failed to read core data: %s", strerror(-n));
450 return (int) n;
451 }
452 if ((size_t) n < size) {
453 log_error("Core data too short.");
454 return -EIO;
455 }
456
457 *ret = field;
458 *ret_size = size + 9;
459
460 field = NULL;
461
462 return 0;
463}
803a3464 464
3f132692
JF
465/* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
466 * 0:/dev/pts/23
467 * pos: 0
468 * flags: 0100002
469 *
470 * 1:/dev/pts/23
471 * pos: 0
472 * flags: 0100002
473 *
474 * 2:/dev/pts/23
475 * pos: 0
476 * flags: 0100002
477 * EOF
478 */
479static int compose_open_fds(pid_t pid, char **open_fds) {
480 _cleanup_fclose_ FILE *stream = NULL;
481 char path[PATH_MAX], line[LINE_MAX];
482 size_t ignored_size;
483 const char *fddelim = "";
484 struct dirent *dent = NULL;
485 _cleanup_closedir_ DIR *proc_fd_dir = NULL;
486 int r = 0;
487
488 assert(pid >= 0);
489 assert(open_fds != NULL);
490
491 sprintf(path, "/proc/"PID_FMT"/fd", pid);
492 proc_fd_dir = opendir(path);
493
494 if (proc_fd_dir == NULL)
495 return -ENOENT;
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;
503 _cleanup_fclose_ FILE *fdinfo = NULL;
504
505 if (dent->d_name[0] == '.' || strcmp(dent->d_name, "..") == 0)
506 continue;
507
508 /* Too long path is unlikely a path to valid file descriptor in /proc/[pid]/fd */
509 /* Skip it. */
510 r = snprintf(path, sizeof(path), "/proc/"PID_FMT"/fd/%s", pid, dent->d_name);
511 if (r >= (int)sizeof(path))
512 continue;
513
514 r = readlink_malloc(path, &fdname);
515 if (r < 0)
516 return r;
517
518 fprintf(stream, "%s%s:%s\n", fddelim, dent->d_name, fdname);
519 fddelim = "\n";
520
521 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
522
523 /* Too long path is unlikely a path to valid file descriptor info in /proc/[pid]/fdinfo */
524 /* Skip it. */
525 r = snprintf(path, sizeof(path), "/proc/"PID_FMT"/fdinfo/%s", pid, dent->d_name);
526 if (r >= (int)sizeof(path))
527 continue;
528
529 fdinfo = fopen(path, "re");
530 if (fdinfo == NULL)
531 continue;
532
533 while(fgets(line, sizeof(line), fdinfo) != NULL)
534 fprintf(stream, "%s%s",
535 line, strchr(line, '\n') == NULL ? "\n" : "");
536 }
537
538 return 0;
539}
540
f5e04665 541int main(int argc, char* argv[]) {
34c10968
LP
542
543 _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
544 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
545 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
3f132692
JF
546 *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL, *core_open_fds = NULL,
547 *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL,
548 *core_cwd = NULL, *core_root = NULL, *core_environ = NULL,
9fe13294 549 *exe = NULL, *comm = NULL, *filename = NULL;
1eef15b1 550 const char *info[_INFO_LEN];
34c10968
LP
551
552 _cleanup_close_ int coredump_fd = -1;
553
3f132692 554 struct iovec iovec[26];
34c10968 555 off_t coredump_size;
f5e04665 556 int r, j = 0;
a035f819 557 uid_t uid, owner_uid;
fee80f69 558 gid_t gid;
a035f819 559 pid_t pid;
34c10968 560 char *t;
3f132692 561 const char *p;
f5e04665 562
34c10968 563 /* Make sure we never enter a loop */
803a3464 564 prctl(PR_SET_DUMPABLE, 0);
f5e04665 565
34c10968
LP
566 /* First, log to a safe place, since we don't know what
567 * crashed and it might be journald which we'd rather not log
568 * to then. */
569 log_set_target(LOG_TARGET_KMSG);
34c10968 570 log_open();
803a3464 571
1eef15b1
ZJS
572 if (argc < INFO_COMM + 1) {
573 log_error("Not enough arguments passed from kernel (%d, expected %d).",
574 argc - 1, INFO_COMM + 1 - 1);
f5e04665
LP
575 r = -EINVAL;
576 goto finish;
577 }
578
34c10968
LP
579 /* Ignore all parse errors */
580 parse_config();
8c9571d0
LP
581
582 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
583 log_debug("Selected compression %s.", yes_no(arg_compress));
34c10968 584
1eef15b1 585 r = parse_uid(argv[INFO_UID + 1], &uid);
f5e04665 586 if (r < 0) {
34c10968
LP
587 log_error("Failed to parse UID.");
588 goto finish;
589 }
803a3464 590
1eef15b1 591 r = parse_pid(argv[INFO_PID + 1], &pid);
34c10968 592 if (r < 0) {
f5e04665 593 log_error("Failed to parse PID.");
f5e04665
LP
594 goto finish;
595 }
596
1eef15b1 597 r = parse_gid(argv[INFO_GID + 1], &gid);
34c10968
LP
598 if (r < 0) {
599 log_error("Failed to parse GID.");
600 goto finish;
601 }
602
1eef15b1 603 if (get_process_comm(pid, &comm) < 0) {
3f85ef0f 604 log_warning("Failed to get COMM, falling back to the command line.");
1eef15b1
ZJS
605 comm = strv_join(argv + INFO_COMM + 1, " ");
606 }
607
608 if (get_process_exe(pid, &exe) < 0)
609 log_warning("Failed to get EXE.");
610
611 info[INFO_PID] = argv[INFO_PID + 1];
612 info[INFO_UID] = argv[INFO_UID + 1];
613 info[INFO_GID] = argv[INFO_GID + 1];
614 info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
615 info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
616 info[INFO_COMM] = comm;
617 info[INFO_EXE] = exe;
618
ba1261bc 619 if (cg_pid_get_unit(pid, &t) >= 0) {
803a3464
LP
620
621 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
803a3464 622
34c10968
LP
623 /* If we are journald, we cut things short,
624 * don't write to the journal, but still
625 * create a coredump. */
626
627 if (arg_storage != COREDUMP_STORAGE_NONE)
628 arg_storage = COREDUMP_STORAGE_EXTERNAL;
629
9fe13294 630 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968
LP
631 if (r < 0)
632 goto finish;
633
9fe13294 634 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
635 if (r < 0)
636 goto finish;
637
9fe13294 638 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
803a3464
LP
639 goto finish;
640 }
641
642 core_unit = strappend("COREDUMP_UNIT=", t);
b7f7c685 643 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
f9045468 644 core_unit = strappend("COREDUMP_USER_UNIT=", t);
803a3464 645
f9045468
MT
646 if (core_unit)
647 IOVEC_SET_STRING(iovec[j++], core_unit);
648
34c10968
LP
649 /* OK, now we know it's not the journal, hence we can make use
650 * of it now. */
803a3464
LP
651 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
652 log_open();
653
1eef15b1 654 core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
f5e04665
LP
655 if (core_pid)
656 IOVEC_SET_STRING(iovec[j++], core_pid);
657
1eef15b1 658 core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
f5e04665
LP
659 if (core_uid)
660 IOVEC_SET_STRING(iovec[j++], core_uid);
661
1eef15b1 662 core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
f5e04665
LP
663 if (core_gid)
664 IOVEC_SET_STRING(iovec[j++], core_gid);
665
1eef15b1 666 core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
f5e04665
LP
667 if (core_signal)
668 IOVEC_SET_STRING(iovec[j++], core_signal);
669
f5e04665
LP
670 if (sd_pid_get_session(pid, &t) >= 0) {
671 core_session = strappend("COREDUMP_SESSION=", t);
672 free(t);
673
674 if (core_session)
675 IOVEC_SET_STRING(iovec[j++], core_session);
676 }
677
a035f819 678 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
7de80bfe
KZ
679 r = asprintf(&core_owner_uid,
680 "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
681 if (r > 0)
a035f819
LP
682 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
683 }
684
685 if (sd_pid_get_slice(pid, &t) >= 0) {
686 core_slice = strappend("COREDUMP_SLICE=", t);
687 free(t);
688
689 if (core_slice)
690 IOVEC_SET_STRING(iovec[j++], core_slice);
691 }
692
1eef15b1
ZJS
693 if (comm) {
694 core_comm = strappend("COREDUMP_COMM=", comm);
695 if (core_comm)
696 IOVEC_SET_STRING(iovec[j++], core_comm);
697 }
698
699 if (exe) {
8d4e028f 700 core_exe = strappend("COREDUMP_EXE=", exe);
f5e04665
LP
701 if (core_exe)
702 IOVEC_SET_STRING(iovec[j++], core_exe);
703 }
704
9bdbc2e2 705 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
f5e04665
LP
706 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
707 free(t);
708
709 if (core_cmdline)
710 IOVEC_SET_STRING(iovec[j++], core_cmdline);
711 }
712
a035f819
LP
713 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
714 core_cgroup = strappend("COREDUMP_CGROUP=", t);
715 free(t);
716
717 if (core_cgroup)
718 IOVEC_SET_STRING(iovec[j++], core_cgroup);
719 }
720
3f132692
JF
721 if (compose_open_fds(pid, &t) >= 0) {
722 core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
723 free(t);
724
725 if (core_open_fds)
726 IOVEC_SET_STRING(iovec[j++], core_open_fds);
727 }
728
729 p = procfs_file_alloca(pid, "status");
730 if (read_full_file(p, &t, NULL) >= 0) {
731 core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
732 free(t);
733
734 if (core_proc_status)
735 IOVEC_SET_STRING(iovec[j++], core_proc_status);
736 }
737
738 p = procfs_file_alloca(pid, "maps");
739 if (read_full_file(p, &t, NULL) >= 0) {
740 core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
741 free(t);
742
743 if (core_proc_maps)
744 IOVEC_SET_STRING(iovec[j++], core_proc_maps);
745 }
746
747 p = procfs_file_alloca(pid, "limits");
748 if (read_full_file(p, &t, NULL) >= 0) {
749 core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
750 free(t);
751
752 if (core_proc_limits)
753 IOVEC_SET_STRING(iovec[j++], core_proc_limits);
754 }
755
756 p = procfs_file_alloca(pid, "cgroup");
757 if (read_full_file(p, &t, NULL) >=0) {
758 core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
759 free(t);
760
761 if (core_proc_cgroup)
762 IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
763 }
764
765 if (get_process_cwd(pid, &t) >= 0) {
766 core_cwd = strappend("COREDUMP_CWD=", t);
767 free(t);
768
769 if (core_cwd)
770 IOVEC_SET_STRING(iovec[j++], core_cwd);
771 }
772
773 if (get_process_root(pid, &t) >= 0) {
774 core_root = strappend("COREDUMP_ROOT=", t);
775 free(t);
776
777 if (core_root)
778 IOVEC_SET_STRING(iovec[j++], core_root);
779 }
780
781 if (get_process_environ(pid, &t) >= 0) {
782 core_environ = strappend("COREDUMP_ENVIRON=", t);
783 free(t);
784
785 if (core_environ)
786 IOVEC_SET_STRING(iovec[j++], core_environ);
787 }
788
1eef15b1 789 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
f5e04665
LP
790 if (core_timestamp)
791 IOVEC_SET_STRING(iovec[j++], core_timestamp);
792
793 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
794 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
795
0dc5d23c
LP
796 /* Vacuum before we write anything again */
797 coredump_vacuum(-1, arg_keep_free, arg_max_use);
798
34c10968 799 /* Always stream the coredump to disk, if that's possible */
9fe13294 800 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
34c10968 801 if (r < 0)
2424a475
ZJS
802 /* skip whole core dumping part */
803 goto log;
34c10968
LP
804
805 /* If we don't want to keep the coredump on disk, remove it
8d4e028f
LP
806 * now, as later on we will lack the privileges for
807 * it. However, we keep the fd to it, so that we can still
808 * process it and log it. */
9fe13294 809 r = maybe_remove_external_coredump(filename, coredump_size);
34c10968
LP
810 if (r < 0)
811 goto finish;
9fe13294
ZJS
812 if (r == 0) {
813 const char *coredump_filename;
814
815 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
816 IOVEC_SET_STRING(iovec[j++], coredump_filename);
817 }
34c10968 818
0dc5d23c
LP
819 /* Vacuum again, but exclude the coredump we just created */
820 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
821
fee80f69
LP
822 /* Now, let's drop privileges to become the user who owns the
823 * segfaulted process and allocate the coredump memory under
b26c631a
KP
824 * the user's uid. This also ensures that the credentials
825 * journald will see are the ones of the coredumping user,
826 * thus making sure the user gets access to the core dump. */
fee80f69
LP
827 if (setresgid(gid, gid, gid) < 0 ||
828 setresuid(uid, uid, uid) < 0) {
829 log_error("Failed to drop privileges: %m");
830 r = -errno;
831 goto finish;
832 }
833
8d4e028f
LP
834#ifdef HAVE_ELFUTILS
835 /* Try to get a strack trace if we can */
836 if (coredump_size <= arg_process_size_max) {
837 _cleanup_free_ char *stacktrace = NULL;
838
839 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
840 if (r >= 0)
1eef15b1 841 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
4d229b31
UTL
842 else if (r == -EINVAL)
843 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
8d4e028f
LP
844 else
845 log_warning("Failed to generate stack trace: %s", strerror(-r));
846 }
847
848 if (!core_message)
849#endif
2424a475 850log:
1eef15b1 851 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
8d4e028f
LP
852 if (core_message)
853 IOVEC_SET_STRING(iovec[j++], core_message);
854
34c10968
LP
855 /* Optionally store the entire coredump in the journal */
856 if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
857 coredump_size <= (off_t) arg_journal_size_max) {
858 size_t sz;
fee80f69 859
34c10968 860 /* Store the coredump itself in the journal */
fee80f69 861
34c10968
LP
862 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
863 if (r >= 0) {
864 iovec[j].iov_base = coredump_data;
865 iovec[j].iov_len = sz;
866 j++;
ca0ceb6f 867 }
fee80f69
LP
868 }
869
f5e04665
LP
870 r = sd_journal_sendv(iovec, j);
871 if (r < 0)
872c8faa 872 log_error("Failed to log coredump: %s", strerror(-r));
f5e04665
LP
873
874finish:
f5e04665
LP
875 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
876}