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