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