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