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