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