]> git.proxmox.com Git - systemd.git/blame - src/journal/coredump.c
Imported Upstream version 219
[systemd.git] / src / journal / coredump.c
CommitLineData
663996b3
MS
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <unistd.h>
24#include <stdio.h>
25#include <sys/prctl.h>
e842803a
MB
26#include <sys/types.h>
27#include <sys/xattr.h>
663996b3 28
5eef597e
MP
29#ifdef HAVE_ELFUTILS
30# include <dwarf.h>
31# include <elfutils/libdwfl.h>
32#endif
33
e735f4d4
MP
34#include "sd-journal.h"
35#include "sd-login.h"
663996b3
MS
36#include "log.h"
37#include "util.h"
f47781d8 38#include "fileio.h"
e842803a 39#include "strv.h"
663996b3
MS
40#include "macro.h"
41#include "mkdir.h"
42#include "special.h"
43#include "cgroup-util.h"
e842803a
MB
44#include "conf-parser.h"
45#include "copy.h"
46#include "stacktrace.h"
47#include "path-util.h"
48#include "compress.h"
e735f4d4
MP
49#include "acl-util.h"
50#include "capability.h"
51#include "journald-native.h"
e842803a
MB
52#include "coredump-vacuum.h"
53
e842803a
MB
54/* The maximum size up to which we process coredumps */
55#define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
56
57/* The maximum size up to which we leave the coredump around on
58 * disk */
59#define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
60
61/* The maximum size up to which we store the coredump in the
62 * journal */
63#define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
663996b3 64
663996b3 65/* Make sure to not make this larger than the maximum journal entry
5eef597e
MP
66 * size. See DATA_SIZE_MAX in journald-native.c. */
67assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
663996b3
MS
68
69enum {
e842803a
MB
70 INFO_PID,
71 INFO_UID,
72 INFO_GID,
73 INFO_SIGNAL,
74 INFO_TIMESTAMP,
75 INFO_COMM,
76 INFO_EXE,
77 _INFO_LEN
78};
79
80typedef enum CoredumpStorage {
81 COREDUMP_STORAGE_NONE,
82 COREDUMP_STORAGE_EXTERNAL,
83 COREDUMP_STORAGE_JOURNAL,
84 COREDUMP_STORAGE_BOTH,
85 _COREDUMP_STORAGE_MAX,
86 _COREDUMP_STORAGE_INVALID = -1
87} CoredumpStorage;
88
89static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
90 [COREDUMP_STORAGE_NONE] = "none",
91 [COREDUMP_STORAGE_EXTERNAL] = "external",
92 [COREDUMP_STORAGE_JOURNAL] = "journal",
93 [COREDUMP_STORAGE_BOTH] = "both",
663996b3
MS
94};
95
e842803a
MB
96DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
97static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
98
99static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
100static bool arg_compress = true;
101static off_t arg_process_size_max = PROCESS_SIZE_MAX;
102static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
103static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
104static off_t arg_keep_free = (off_t) -1;
105static off_t arg_max_use = (off_t) -1;
106
107static int parse_config(void) {
108 static const ConfigTableItem items[] = {
109 { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
110 { "Coredump", "Compress", config_parse_bool, 0, &arg_compress },
111 { "Coredump", "ProcessSizeMax", config_parse_iec_off, 0, &arg_process_size_max },
112 { "Coredump", "ExternalSizeMax", config_parse_iec_off, 0, &arg_external_size_max },
113 { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
114 { "Coredump", "KeepFree", config_parse_iec_off, 0, &arg_keep_free },
115 { "Coredump", "MaxUse", config_parse_iec_off, 0, &arg_max_use },
116 {}
117 };
118
f47781d8
MP
119 return config_parse_many("/etc/systemd/coredump.conf",
120 CONF_DIRS_NULSTR("systemd/coredump.conf"),
121 "Coredump\0",
122 config_item_table_lookup, items,
123 false, NULL);
e842803a
MB
124}
125
126static int fix_acl(int fd, uid_t uid) {
127
128#ifdef HAVE_ACL
129 _cleanup_(acl_freep) acl_t acl = NULL;
130 acl_entry_t entry;
131 acl_permset_t permset;
132
133 assert(fd >= 0);
134
135 if (uid <= SYSTEM_UID_MAX)
136 return 0;
137
138 /* Make sure normal users can read (but not write or delete)
139 * their own coredumps */
140
141 acl = acl_get_fd(fd);
f47781d8
MP
142 if (!acl)
143 return log_error_errno(errno, "Failed to get ACL: %m");
e842803a
MB
144
145 if (acl_create_entry(&acl, &entry) < 0 ||
146 acl_set_tag_type(entry, ACL_USER) < 0 ||
147 acl_set_qualifier(entry, &uid) < 0) {
f47781d8 148 log_error_errno(errno, "Failed to patch ACL: %m");
e842803a
MB
149 return -errno;
150 }
151
152 if (acl_get_permset(entry, &permset) < 0 ||
153 acl_add_perm(permset, ACL_READ) < 0 ||
154 calc_acl_mask_if_needed(&acl) < 0) {
f47781d8 155 log_warning_errno(errno, "Failed to patch ACL: %m");
e842803a
MB
156 return -errno;
157 }
158
f47781d8
MP
159 if (acl_set_fd(fd, acl) < 0)
160 return log_error_errno(errno, "Failed to apply ACL: %m");
e842803a
MB
161#endif
162
163 return 0;
164}
165
166static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
167
168 static const char * const xattrs[_INFO_LEN] = {
169 [INFO_PID] = "user.coredump.pid",
170 [INFO_UID] = "user.coredump.uid",
171 [INFO_GID] = "user.coredump.gid",
172 [INFO_SIGNAL] = "user.coredump.signal",
173 [INFO_TIMESTAMP] = "user.coredump.timestamp",
174 [INFO_COMM] = "user.coredump.comm",
175 [INFO_EXE] = "user.coredump.exe",
176 };
177
178 int r = 0;
179 unsigned i;
180
181 assert(fd >= 0);
182
183 /* Attach some metadata to coredumps via extended
184 * attributes. Just because we can. */
185
186 for (i = 0; i < _INFO_LEN; i++) {
187 int k;
188
189 if (isempty(info[i]) || !xattrs[i])
190 continue;
191
192 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
193 if (k < 0 && r == 0)
194 r = -errno;
195 }
196
197 return r;
198}
199
200#define filename_escape(s) xescape((s), "./ ")
201
202static int fix_permissions(
203 int fd,
204 const char *filename,
205 const char *target,
206 const char *info[_INFO_LEN],
207 uid_t uid) {
208
209 assert(fd >= 0);
210 assert(filename);
211 assert(target);
212 assert(info);
213
214 /* Ignore errors on these */
215 fchmod(fd, 0640);
216 fix_acl(fd, uid);
217 fix_xattr(fd, info);
218
f47781d8
MP
219 if (fsync(fd) < 0)
220 return log_error_errno(errno, "Failed to sync coredump %s: %m", filename);
e842803a 221
f47781d8
MP
222 if (rename(filename, target) < 0)
223 return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
e842803a
MB
224
225 return 0;
226}
227
228static int maybe_remove_external_coredump(const char *filename, off_t size) {
229
230 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
231
232 if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
233 size <= arg_external_size_max)
234 return 0;
235
236 if (!filename)
237 return 1;
238
f47781d8
MP
239 if (unlink(filename) < 0 && errno != ENOENT)
240 return log_error_errno(errno, "Failed to unlink %s: %m", filename);
e842803a
MB
241
242 return 1;
243}
244
245static int make_filename(const char *info[_INFO_LEN], char **ret) {
246 _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
247 sd_id128_t boot;
248 int r;
249
250 assert(info);
251
252 c = filename_escape(info[INFO_COMM]);
253 if (!c)
254 return -ENOMEM;
255
256 u = filename_escape(info[INFO_UID]);
257 if (!u)
258 return -ENOMEM;
259
260 r = sd_id128_get_boot(&boot);
261 if (r < 0)
262 return r;
263
264 p = filename_escape(info[INFO_PID]);
265 if (!p)
266 return -ENOMEM;
663996b3 267
e842803a
MB
268 t = filename_escape(info[INFO_TIMESTAMP]);
269 if (!t)
270 return -ENOMEM;
271
272 if (asprintf(ret,
273 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
274 c,
275 u,
276 SD_ID128_FORMAT_VAL(boot),
277 p,
278 t) < 0)
279 return -ENOMEM;
280
281 return 0;
282}
283
284static int save_external_coredump(
285 const char *info[_INFO_LEN],
286 uid_t uid,
287 char **ret_filename,
288 int *ret_fd,
289 off_t *ret_size) {
290
291 _cleanup_free_ char *fn = NULL, *tmp = NULL;
292 _cleanup_close_ int fd = -1;
293 struct stat st;
294 int r;
295
296 assert(info);
297 assert(ret_filename);
298 assert(ret_fd);
299 assert(ret_size);
300
301 r = make_filename(info, &fn);
f47781d8
MP
302 if (r < 0)
303 return log_error_errno(r, "Failed to determine coredump file name: %m");
e842803a 304
e735f4d4
MP
305 r = tempfn_random(fn, &tmp);
306 if (r < 0)
307 return log_error_errno(r, "Failed to determine temporary file name: %m");
663996b3
MS
308
309 mkdir_p_label("/var/lib/systemd/coredump", 0755);
310
e842803a 311 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
f47781d8
MP
312 if (fd < 0)
313 return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
663996b3 314
e735f4d4 315 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max, false);
f47781d8 316 if (r == -EFBIG) {
e842803a
MB
317 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
318 goto fail;
319 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
320 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
321 goto fail;
322 } else if (r < 0) {
f47781d8 323 log_error_errno(r, "Failed to dump coredump to file: %m");
e842803a
MB
324 goto fail;
325 }
326
327 if (fstat(fd, &st) < 0) {
f47781d8 328 log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
e842803a
MB
329 goto fail;
330 }
331
332 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
f47781d8 333 log_error_errno(errno, "Failed to seek on %s: %m", tmp);
e842803a
MB
334 goto fail;
335 }
336
5eef597e 337#if defined(HAVE_XZ) || defined(HAVE_LZ4)
e842803a
MB
338 /* If we will remove the coredump anyway, do not compress. */
339 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
340 && arg_compress) {
341
342 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
343 _cleanup_close_ int fd_compressed = -1;
663996b3 344
5eef597e 345 fn_compressed = strappend(fn, COMPRESSED_EXT);
e842803a 346 if (!fn_compressed) {
5eef597e 347 log_oom();
e842803a
MB
348 goto uncompressed;
349 }
350
e735f4d4
MP
351 r = tempfn_random(fn_compressed, &tmp_compressed);
352 if (r < 0) {
353 log_error_errno(r, "Failed to determine temporary file name for %s: %m", fn_compressed);
e842803a
MB
354 goto uncompressed;
355 }
663996b3 356
e842803a
MB
357 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
358 if (fd_compressed < 0) {
f47781d8 359 log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
e842803a 360 goto uncompressed;
663996b3
MS
361 }
362
5eef597e 363 r = compress_stream(fd, fd_compressed, -1);
e842803a 364 if (r < 0) {
f47781d8 365 log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
e842803a 366 goto fail_compressed;
663996b3 367 }
e842803a
MB
368
369 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
370 if (r < 0)
371 goto fail_compressed;
372
373 /* OK, this worked, we can get rid of the uncompressed version now */
374 unlink_noerrno(tmp);
375
376 *ret_filename = fn_compressed; /* compressed */
377 *ret_fd = fd; /* uncompressed */
378 *ret_size = st.st_size; /* uncompressed */
379
380 fn_compressed = NULL;
381 fd = -1;
382
383 return 0;
384
385 fail_compressed:
386 unlink_noerrno(tmp_compressed);
663996b3 387 }
e842803a
MB
388
389uncompressed:
5eef597e 390#endif
e842803a
MB
391 r = fix_permissions(fd, tmp, fn, info, uid);
392 if (r < 0)
393 goto fail;
394
395 *ret_filename = fn;
396 *ret_fd = fd;
397 *ret_size = st.st_size;
398
399 fn = NULL;
400 fd = -1;
401
402 return 0;
403
404fail:
405 unlink_noerrno(tmp);
406 return r;
407}
663996b3 408
e842803a
MB
409static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
410 _cleanup_free_ char *field = NULL;
411 ssize_t n;
412
413 assert(fd >= 0);
414 assert(ret);
415 assert(ret_size);
663996b3 416
f47781d8
MP
417 if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
418 return log_warning_errno(errno, "Failed to seek: %m");
663996b3 419
e842803a
MB
420 field = malloc(9 + size);
421 if (!field) {
422 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
423 return -ENOMEM;
424 }
425
426 memcpy(field, "COREDUMP=", 9);
427
428 n = read(fd, field + 9, size);
f47781d8
MP
429 if (n < 0)
430 return log_error_errno((int) n, "Failed to read core data: %m");
e842803a
MB
431 if ((size_t) n < size) {
432 log_error("Core data too short.");
433 return -EIO;
434 }
435
436 *ret = field;
437 *ret_size = size + 9;
438
439 field = NULL;
440
663996b3
MS
441 return 0;
442}
443
f47781d8
MP
444/* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
445 * 0:/dev/pts/23
446 * pos: 0
447 * flags: 0100002
448 *
449 * 1:/dev/pts/23
450 * pos: 0
451 * flags: 0100002
452 *
453 * 2:/dev/pts/23
454 * pos: 0
455 * flags: 0100002
456 * EOF
457 */
458static int compose_open_fds(pid_t pid, char **open_fds) {
459 _cleanup_closedir_ DIR *proc_fd_dir = NULL;
460 _cleanup_close_ int proc_fdinfo_fd = -1;
461 _cleanup_free_ char *buffer = NULL;
462 _cleanup_fclose_ FILE *stream = NULL;
463 const char *fddelim = "", *path;
464 struct dirent *dent = NULL;
465 size_t size = 0;
466 int r = 0;
467
468 assert(pid >= 0);
469 assert(open_fds != NULL);
470
471 path = procfs_file_alloca(pid, "fd");
472 proc_fd_dir = opendir(path);
473 if (!proc_fd_dir)
474 return -errno;
475
476 proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo", O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
477 if (proc_fdinfo_fd < 0)
478 return -errno;
479
480 stream = open_memstream(&buffer, &size);
481 if (!stream)
482 return -ENOMEM;
483
484 FOREACH_DIRENT(dent, proc_fd_dir, return -errno) {
485 _cleanup_fclose_ FILE *fdinfo = NULL;
486 _cleanup_free_ char *fdname = NULL;
487 char line[LINE_MAX];
488 int fd;
489
490 r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname);
491 if (r < 0)
492 return r;
493
494 fprintf(stream, "%s%s:%s\n", fddelim, dent->d_name, fdname);
495 fddelim = "\n";
496
497 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
498 fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
499 if (fd < 0)
500 continue;
501
502 fdinfo = fdopen(fd, "re");
503 if (fdinfo == NULL) {
504 close(fd);
505 continue;
506 }
507
508 FOREACH_LINE(line, fdinfo, break) {
509 fputs(line, stream);
510 if (!endswith(line, "\n"))
511 fputc('\n', stream);
512 }
513 }
514
515 errno = 0;
516 fclose(stream);
517 stream = NULL;
518
519 if (errno != 0)
520 return -errno;
521
522 *open_fds = buffer;
523 buffer = NULL;
524
525 return 0;
526}
527
663996b3 528int main(int argc, char* argv[]) {
e842803a 529
f47781d8
MP
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;
e842803a
MB
544 const char *info[_INFO_LEN];
545
546 _cleanup_close_ int coredump_fd = -1;
547
f47781d8 548 struct iovec iovec[26];
e842803a
MB
549 off_t coredump_size;
550 int r, j = 0;
551 uid_t uid, owner_uid;
552 gid_t gid;
553 pid_t pid;
554 char *t;
f47781d8 555 const char *p;
663996b3 556
e842803a 557 /* Make sure we never enter a loop */
663996b3
MS
558 prctl(PR_SET_DUMPABLE, 0);
559
e842803a
MB
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);
564 log_open();
663996b3 565
e842803a
MB
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);
663996b3
MS
569 r = -EINVAL;
570 goto finish;
571 }
572
e842803a
MB
573 /* Ignore all parse errors */
574 parse_config();
575
576 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
577 log_debug("Selected compression %s.", yes_no(arg_compress));
578
579 r = parse_uid(argv[INFO_UID + 1], &uid);
663996b3 580 if (r < 0) {
e842803a
MB
581 log_error("Failed to parse UID.");
582 goto finish;
583 }
663996b3 584
e842803a
MB
585 r = parse_pid(argv[INFO_PID + 1], &pid);
586 if (r < 0) {
663996b3
MS
587 log_error("Failed to parse PID.");
588 goto finish;
589 }
590
e842803a
MB
591 r = parse_gid(argv[INFO_GID + 1], &gid);
592 if (r < 0) {
593 log_error("Failed to parse GID.");
594 goto finish;
595 }
596
597 if (get_process_comm(pid, &comm) < 0) {
f47781d8 598 log_warning("Failed to get COMM, falling back to the command line.");
e842803a
MB
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
663996b3
MS
613 if (cg_pid_get_unit(pid, &t) >= 0) {
614
615 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
f47781d8 616 free(t);
663996b3 617
e842803a
MB
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
625 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
626 if (r < 0)
627 goto finish;
628
629 r = maybe_remove_external_coredump(filename, coredump_size);
630 if (r < 0)
631 goto finish;
632
633 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
663996b3
MS
634 goto finish;
635 }
636
e735f4d4 637 core_unit = strjoina("COREDUMP_UNIT=", t);
f47781d8
MP
638 free(t);
639
640 } else if (cg_pid_get_user_unit(pid, &t) >= 0) {
e735f4d4 641 core_unit = strjoina("COREDUMP_USER_UNIT=", t);
f47781d8
MP
642 free(t);
643 }
663996b3
MS
644
645 if (core_unit)
646 IOVEC_SET_STRING(iovec[j++], core_unit);
647
e842803a
MB
648 /* OK, now we know it's not the journal, hence we can make use
649 * of it now. */
663996b3
MS
650 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
651 log_open();
652
e735f4d4 653 core_pid = strjoina("COREDUMP_PID=", info[INFO_PID]);
f47781d8 654 IOVEC_SET_STRING(iovec[j++], core_pid);
663996b3 655
e735f4d4 656 core_uid = strjoina("COREDUMP_UID=", info[INFO_UID]);
f47781d8 657 IOVEC_SET_STRING(iovec[j++], core_uid);
663996b3 658
e735f4d4 659 core_gid = strjoina("COREDUMP_GID=", info[INFO_GID]);
f47781d8 660 IOVEC_SET_STRING(iovec[j++], core_gid);
663996b3 661
e735f4d4 662 core_signal = strjoina("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
f47781d8 663 IOVEC_SET_STRING(iovec[j++], core_signal);
663996b3 664
663996b3 665 if (sd_pid_get_session(pid, &t) >= 0) {
e735f4d4 666 core_session = strjoina("COREDUMP_SESSION=", t);
663996b3
MS
667 free(t);
668
f47781d8 669 IOVEC_SET_STRING(iovec[j++], core_session);
663996b3
MS
670 }
671
e842803a 672 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
5eef597e
MP
673 r = asprintf(&core_owner_uid,
674 "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
675 if (r > 0)
e842803a
MB
676 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
677 }
678
679 if (sd_pid_get_slice(pid, &t) >= 0) {
e735f4d4 680 core_slice = strjoina("COREDUMP_SLICE=", t);
663996b3
MS
681 free(t);
682
f47781d8 683 IOVEC_SET_STRING(iovec[j++], core_slice);
e842803a
MB
684 }
685
686 if (comm) {
e735f4d4 687 core_comm = strjoina("COREDUMP_COMM=", comm);
f47781d8 688 IOVEC_SET_STRING(iovec[j++], core_comm);
e842803a
MB
689 }
690
691 if (exe) {
e735f4d4 692 core_exe = strjoina("COREDUMP_EXE=", exe);
f47781d8 693 IOVEC_SET_STRING(iovec[j++], core_exe);
663996b3
MS
694 }
695
696 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
e735f4d4 697 core_cmdline = strjoina("COREDUMP_CMDLINE=", t);
663996b3
MS
698 free(t);
699
f47781d8 700 IOVEC_SET_STRING(iovec[j++], core_cmdline);
663996b3
MS
701 }
702
e842803a 703 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
e735f4d4 704 core_cgroup = strjoina("COREDUMP_CGROUP=", t);
f47781d8
MP
705 free(t);
706
707 IOVEC_SET_STRING(iovec[j++], core_cgroup);
708 }
709
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) {
e735f4d4 755 core_cwd = strjoina("COREDUMP_CWD=", t);
f47781d8
MP
756 free(t);
757
758 IOVEC_SET_STRING(iovec[j++], core_cwd);
759 }
760
761 if (get_process_root(pid, &t) >= 0) {
e735f4d4 762 core_root = strjoina("COREDUMP_ROOT=", t);
f47781d8
MP
763 free(t);
764
765 IOVEC_SET_STRING(iovec[j++], core_root);
766 }
767
768 if (get_process_environ(pid, &t) >= 0) {
769 core_environ = strappend("COREDUMP_ENVIRON=", t);
e842803a
MB
770 free(t);
771
f47781d8
MP
772 if (core_environ)
773 IOVEC_SET_STRING(iovec[j++], core_environ);
e842803a
MB
774 }
775
776 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
663996b3
MS
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
e842803a
MB
783 /* Vacuum before we write anything again */
784 coredump_vacuum(-1, arg_keep_free, arg_max_use);
785
786 /* Always stream the coredump to disk, if that's possible */
787 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
788 if (r < 0)
789 /* skip whole core dumping part */
790 goto log;
791
792 /* If we don't want to keep the coredump on disk, remove it
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. */
796 r = maybe_remove_external_coredump(filename, coredump_size);
797 if (r < 0)
798 goto finish;
799 if (r == 0) {
800 const char *coredump_filename;
801
e735f4d4 802 coredump_filename = strjoina("COREDUMP_FILENAME=", filename);
e842803a
MB
803 IOVEC_SET_STRING(iovec[j++], coredump_filename);
804 }
805
806 /* Vacuum again, but exclude the coredump we just created */
807 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
663996b3
MS
808
809 /* Now, let's drop privileges to become the user who owns the
810 * segfaulted process and allocate the coredump memory under
5eef597e
MP
811 * the user's uid. This also ensures that the credentials
812 * journald will see are the ones of the coredumping user,
e735f4d4
MP
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");
663996b3
MS
819 goto finish;
820 }
821
e842803a
MB
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;
663996b3 826
e842803a
MB
827 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
828 if (r >= 0)
829 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
5eef597e
MP
830 else if (r == -EINVAL)
831 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
e842803a 832 else
f47781d8 833 log_warning_errno(r, "Failed to generate stack trace: %m");
e842803a 834 }
663996b3 835
e842803a
MB
836 if (!core_message)
837#endif
838log:
839 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
840 if (core_message)
841 IOVEC_SET_STRING(iovec[j++], core_message);
663996b3 842
e842803a
MB
843 /* Optionally store the entire coredump in the journal */
844 if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
845 coredump_size <= (off_t) arg_journal_size_max) {
846 size_t sz;
14228c0d 847
e842803a
MB
848 /* Store the coredump itself in the journal */
849
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++;
663996b3
MS
855 }
856 }
857
663996b3
MS
858 r = sd_journal_sendv(iovec, j);
859 if (r < 0)
f47781d8 860 log_error_errno(r, "Failed to log coredump: %m");
663996b3
MS
861
862finish:
863 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
864}