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