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