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