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