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