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