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