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