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