]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/coredump.c
Merge pull request #1226 from poettering/coccinelle-fixes3
[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, NULL, &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, NULL, &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 stream = safe_fclose(stream);
516
517 if (errno != 0)
518 return -errno;
519
520 *open_fds = buffer;
521 buffer = NULL;
522
523 return 0;
524 }
525
526 int main(int argc, char* argv[]) {
527
528 /* The small core field we allocate on the stack, to keep things simple */
529 char
530 *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
531 *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL,
532 *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL,
533 *core_slice = NULL;
534
535 /* The larger ones we allocate on the heap */
536 _cleanup_free_ char
537 *core_timestamp = NULL, *core_message = NULL, *coredump_data = NULL, *core_owner_uid = NULL,
538 *core_open_fds = NULL, *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL,
539 *core_proc_cgroup = NULL, *core_environ = NULL;
540
541 _cleanup_free_ char *exe = NULL, *comm = NULL, *filename = NULL;
542 const char *info[_INFO_LEN];
543
544 _cleanup_close_ int coredump_fd = -1;
545
546 struct iovec iovec[26];
547 off_t coredump_size;
548 int r, j = 0;
549 uid_t uid, owner_uid;
550 gid_t gid;
551 pid_t pid;
552 char *t;
553 const char *p;
554
555 /* Make sure we never enter a loop */
556 prctl(PR_SET_DUMPABLE, 0);
557
558 /* First, log to a safe place, since we don't know what
559 * crashed and it might be journald which we'd rather not log
560 * to then. */
561 log_set_target(LOG_TARGET_KMSG);
562 log_open();
563
564 if (argc < INFO_COMM + 1) {
565 log_error("Not enough arguments passed from kernel (%d, expected %d).",
566 argc - 1, INFO_COMM + 1 - 1);
567 r = -EINVAL;
568 goto finish;
569 }
570
571 /* Ignore all parse errors */
572 parse_config();
573
574 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
575 log_debug("Selected compression %s.", yes_no(arg_compress));
576
577 r = parse_uid(argv[INFO_UID + 1], &uid);
578 if (r < 0) {
579 log_error("Failed to parse UID.");
580 goto finish;
581 }
582
583 r = parse_pid(argv[INFO_PID + 1], &pid);
584 if (r < 0) {
585 log_error("Failed to parse PID.");
586 goto finish;
587 }
588
589 r = parse_gid(argv[INFO_GID + 1], &gid);
590 if (r < 0) {
591 log_error("Failed to parse GID.");
592 goto finish;
593 }
594
595 if (get_process_comm(pid, &comm) < 0) {
596 log_warning("Failed to get COMM, falling back to the command line.");
597 comm = strv_join(argv + INFO_COMM + 1, " ");
598 }
599
600 if (get_process_exe(pid, &exe) < 0)
601 log_warning("Failed to get EXE.");
602
603 info[INFO_PID] = argv[INFO_PID + 1];
604 info[INFO_UID] = argv[INFO_UID + 1];
605 info[INFO_GID] = argv[INFO_GID + 1];
606 info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
607 info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
608 info[INFO_COMM] = comm;
609 info[INFO_EXE] = exe;
610
611 if (cg_pid_get_unit(pid, &t) >= 0) {
612
613 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
614 free(t);
615
616 /* If we are journald, we cut things short,
617 * don't write to the journal, but still
618 * create a coredump. */
619
620 if (arg_storage != COREDUMP_STORAGE_NONE)
621 arg_storage = COREDUMP_STORAGE_EXTERNAL;
622
623 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
624 if (r < 0)
625 goto finish;
626
627 r = maybe_remove_external_coredump(filename, coredump_size);
628 if (r < 0)
629 goto finish;
630
631 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
632 goto finish;
633 }
634
635 core_unit = strjoina("COREDUMP_UNIT=", t);
636 free(t);
637
638 } else if (cg_pid_get_user_unit(pid, &t) >= 0) {
639 core_unit = strjoina("COREDUMP_USER_UNIT=", t);
640 free(t);
641 }
642
643 if (core_unit)
644 IOVEC_SET_STRING(iovec[j++], core_unit);
645
646 /* OK, now we know it's not the journal, hence we can make use
647 * of it now. */
648 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
649 log_open();
650
651 core_pid = strjoina("COREDUMP_PID=", info[INFO_PID]);
652 IOVEC_SET_STRING(iovec[j++], core_pid);
653
654 core_uid = strjoina("COREDUMP_UID=", info[INFO_UID]);
655 IOVEC_SET_STRING(iovec[j++], core_uid);
656
657 core_gid = strjoina("COREDUMP_GID=", info[INFO_GID]);
658 IOVEC_SET_STRING(iovec[j++], core_gid);
659
660 core_signal = strjoina("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
661 IOVEC_SET_STRING(iovec[j++], core_signal);
662
663 if (sd_pid_get_session(pid, &t) >= 0) {
664 core_session = strjoina("COREDUMP_SESSION=", t);
665 free(t);
666
667 IOVEC_SET_STRING(iovec[j++], core_session);
668 }
669
670 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
671 r = asprintf(&core_owner_uid,
672 "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
673 if (r > 0)
674 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
675 }
676
677 if (sd_pid_get_slice(pid, &t) >= 0) {
678 core_slice = strjoina("COREDUMP_SLICE=", t);
679 free(t);
680
681 IOVEC_SET_STRING(iovec[j++], core_slice);
682 }
683
684 if (comm) {
685 core_comm = strjoina("COREDUMP_COMM=", comm);
686 IOVEC_SET_STRING(iovec[j++], core_comm);
687 }
688
689 if (exe) {
690 core_exe = strjoina("COREDUMP_EXE=", exe);
691 IOVEC_SET_STRING(iovec[j++], core_exe);
692 }
693
694 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
695 core_cmdline = strjoina("COREDUMP_CMDLINE=", t);
696 free(t);
697
698 IOVEC_SET_STRING(iovec[j++], core_cmdline);
699 }
700
701 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
702 core_cgroup = strjoina("COREDUMP_CGROUP=", t);
703 free(t);
704
705 IOVEC_SET_STRING(iovec[j++], core_cgroup);
706 }
707
708 if (compose_open_fds(pid, &t) >= 0) {
709 core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
710 free(t);
711
712 if (core_open_fds)
713 IOVEC_SET_STRING(iovec[j++], core_open_fds);
714 }
715
716 p = procfs_file_alloca(pid, "status");
717 if (read_full_file(p, &t, NULL) >= 0) {
718 core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
719 free(t);
720
721 if (core_proc_status)
722 IOVEC_SET_STRING(iovec[j++], core_proc_status);
723 }
724
725 p = procfs_file_alloca(pid, "maps");
726 if (read_full_file(p, &t, NULL) >= 0) {
727 core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
728 free(t);
729
730 if (core_proc_maps)
731 IOVEC_SET_STRING(iovec[j++], core_proc_maps);
732 }
733
734 p = procfs_file_alloca(pid, "limits");
735 if (read_full_file(p, &t, NULL) >= 0) {
736 core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
737 free(t);
738
739 if (core_proc_limits)
740 IOVEC_SET_STRING(iovec[j++], core_proc_limits);
741 }
742
743 p = procfs_file_alloca(pid, "cgroup");
744 if (read_full_file(p, &t, NULL) >=0) {
745 core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
746 free(t);
747
748 if (core_proc_cgroup)
749 IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
750 }
751
752 if (get_process_cwd(pid, &t) >= 0) {
753 core_cwd = strjoina("COREDUMP_CWD=", t);
754 free(t);
755
756 IOVEC_SET_STRING(iovec[j++], core_cwd);
757 }
758
759 if (get_process_root(pid, &t) >= 0) {
760 core_root = strjoina("COREDUMP_ROOT=", t);
761 free(t);
762
763 IOVEC_SET_STRING(iovec[j++], core_root);
764 }
765
766 if (get_process_environ(pid, &t) >= 0) {
767 core_environ = strappend("COREDUMP_ENVIRON=", t);
768 free(t);
769
770 if (core_environ)
771 IOVEC_SET_STRING(iovec[j++], core_environ);
772 }
773
774 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
775 if (core_timestamp)
776 IOVEC_SET_STRING(iovec[j++], core_timestamp);
777
778 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
779 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
780
781 /* Vacuum before we write anything again */
782 coredump_vacuum(-1, arg_keep_free, arg_max_use);
783
784 /* Always stream the coredump to disk, if that's possible */
785 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
786 if (r < 0)
787 /* skip whole core dumping part */
788 goto log;
789
790 /* If we don't want to keep the coredump on disk, remove it
791 * now, as later on we will lack the privileges for
792 * it. However, we keep the fd to it, so that we can still
793 * process it and log it. */
794 r = maybe_remove_external_coredump(filename, coredump_size);
795 if (r < 0)
796 goto finish;
797 if (r == 0) {
798 const char *coredump_filename;
799
800 coredump_filename = strjoina("COREDUMP_FILENAME=", filename);
801 IOVEC_SET_STRING(iovec[j++], coredump_filename);
802 }
803
804 /* Vacuum again, but exclude the coredump we just created */
805 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
806
807 /* Now, let's drop privileges to become the user who owns the
808 * segfaulted process and allocate the coredump memory under
809 * the user's uid. This also ensures that the credentials
810 * journald will see are the ones of the coredumping user,
811 * thus making sure the user gets access to the core
812 * dump. Let's also get rid of all capabilities, if we run as
813 * root, we won't need them anymore. */
814 r = drop_privileges(uid, gid, 0);
815 if (r < 0) {
816 log_error_errno(r, "Failed to drop privileges: %m");
817 goto finish;
818 }
819
820 #ifdef HAVE_ELFUTILS
821 /* Try to get a strack trace if we can */
822 if (coredump_size <= arg_process_size_max) {
823 _cleanup_free_ char *stacktrace = NULL;
824
825 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
826 if (r >= 0)
827 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
828 else if (r == -EINVAL)
829 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
830 else
831 log_warning_errno(r, "Failed to generate stack trace: %m");
832 }
833
834 if (!core_message)
835 #endif
836 log:
837 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
838 if (core_message)
839 IOVEC_SET_STRING(iovec[j++], core_message);
840
841 /* Optionally store the entire coredump in the journal */
842 if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
843 coredump_size <= (off_t) arg_journal_size_max) {
844 size_t sz = 0;
845
846 /* Store the coredump itself in the journal */
847
848 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
849 if (r >= 0) {
850 iovec[j].iov_base = coredump_data;
851 iovec[j].iov_len = sz;
852 j++;
853 }
854 }
855
856 r = sd_journal_sendv(iovec, j);
857 if (r < 0)
858 log_error_errno(r, "Failed to log coredump: %m");
859
860 finish:
861 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
862 }