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