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