1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
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.
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.
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/>.
25 #include <sys/prctl.h>
26 #include <sys/types.h>
27 #include <sys/xattr.h>
31 # include <elfutils/libdwfl.h>
34 #include "systemd/sd-journal.h"
35 #include "systemd/sd-login.h"
44 #include "cgroup-util.h"
45 #include "journald-native.h"
46 #include "conf-parser.h"
48 #include "stacktrace.h"
49 #include "path-util.h"
51 #include "coredump-vacuum.h"
55 # include "acl-util.h"
58 /* The maximum size up to which we process coredumps */
59 #define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
61 /* The maximum size up to which we leave the coredump around on
63 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
65 /* The maximum size up to which we store the coredump in the
67 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
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);
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
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",
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");
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;
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 },
123 return config_parse(NULL, "/etc/systemd/coredump.conf", NULL,
125 config_item_table_lookup, items,
126 false, false, true, NULL);
129 static int fix_acl(int fd, uid_t uid) {
132 _cleanup_(acl_freep) acl_t acl = NULL;
134 acl_permset_t permset;
138 if (uid <= SYSTEM_UID_MAX)
141 /* Make sure normal users can read (but not write or delete)
142 * their own coredumps */
144 acl = acl_get_fd(fd);
146 return log_error_errno(errno, "Failed to get ACL: %m");
148 if (acl_create_entry(&acl, &entry) < 0 ||
149 acl_set_tag_type(entry, ACL_USER) < 0 ||
150 acl_set_qualifier(entry, &uid) < 0) {
151 log_error_errno(errno, "Failed to patch ACL: %m");
155 if (acl_get_permset(entry, &permset) < 0 ||
156 acl_add_perm(permset, ACL_READ) < 0 ||
157 calc_acl_mask_if_needed(&acl) < 0) {
158 log_warning_errno(errno, "Failed to patch ACL: %m");
162 if (acl_set_fd(fd, acl) < 0)
163 return log_error_errno(errno, "Failed to apply ACL: %m");
169 static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
171 static const char * const xattrs[_INFO_LEN] = {
172 [INFO_PID] = "user.coredump.pid",
173 [INFO_UID] = "user.coredump.uid",
174 [INFO_GID] = "user.coredump.gid",
175 [INFO_SIGNAL] = "user.coredump.signal",
176 [INFO_TIMESTAMP] = "user.coredump.timestamp",
177 [INFO_COMM] = "user.coredump.comm",
178 [INFO_EXE] = "user.coredump.exe",
186 /* Attach some metadata to coredumps via extended
187 * attributes. Just because we can. */
189 for (i = 0; i < _INFO_LEN; i++) {
192 if (isempty(info[i]) || !xattrs[i])
195 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
203 #define filename_escape(s) xescape((s), "./ ")
205 static int fix_permissions(
207 const char *filename,
209 const char *info[_INFO_LEN],
217 /* Ignore errors on these */
223 return log_error_errno(errno, "Failed to sync coredump %s: %m", filename);
225 if (rename(filename, target) < 0)
226 return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
231 static int maybe_remove_external_coredump(const char *filename, off_t size) {
233 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
235 if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
236 size <= arg_external_size_max)
242 if (unlink(filename) < 0 && errno != ENOENT)
243 return log_error_errno(errno, "Failed to unlink %s: %m", filename);
248 static int make_filename(const char *info[_INFO_LEN], char **ret) {
249 _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
255 c = filename_escape(info[INFO_COMM]);
259 u = filename_escape(info[INFO_UID]);
263 r = sd_id128_get_boot(&boot);
267 p = filename_escape(info[INFO_PID]);
271 t = filename_escape(info[INFO_TIMESTAMP]);
276 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
279 SD_ID128_FORMAT_VAL(boot),
287 static int save_external_coredump(
288 const char *info[_INFO_LEN],
294 _cleanup_free_ char *fn = NULL, *tmp = NULL;
295 _cleanup_close_ int fd = -1;
300 assert(ret_filename);
304 r = make_filename(info, &fn);
306 return log_error_errno(r, "Failed to determine coredump file name: %m");
308 tmp = tempfn_random(fn);
312 mkdir_p_label("/var/lib/systemd/coredump", 0755);
314 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
316 return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
318 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
320 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
322 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
323 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
326 log_error_errno(r, "Failed to dump coredump to file: %m");
330 if (fstat(fd, &st) < 0) {
331 log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
335 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
336 log_error_errno(errno, "Failed to seek on %s: %m", tmp);
340 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
341 /* If we will remove the coredump anyway, do not compress. */
342 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
345 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
346 _cleanup_close_ int fd_compressed = -1;
348 fn_compressed = strappend(fn, COMPRESSED_EXT);
349 if (!fn_compressed) {
354 tmp_compressed = tempfn_random(fn_compressed);
355 if (!tmp_compressed) {
360 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
361 if (fd_compressed < 0) {
362 log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
366 r = compress_stream(fd, fd_compressed, -1);
368 log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
369 goto fail_compressed;
372 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
374 goto fail_compressed;
376 /* OK, this worked, we can get rid of the uncompressed version now */
379 *ret_filename = fn_compressed; /* compressed */
380 *ret_fd = fd; /* uncompressed */
381 *ret_size = st.st_size; /* uncompressed */
383 fn_compressed = NULL;
389 unlink_noerrno(tmp_compressed);
394 r = fix_permissions(fd, tmp, fn, info, uid);
400 *ret_size = st.st_size;
412 static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
413 _cleanup_free_ char *field = NULL;
420 if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
421 return log_warning_errno(errno, "Failed to seek: %m");
423 field = malloc(9 + size);
425 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
429 memcpy(field, "COREDUMP=", 9);
431 n = read(fd, field + 9, size);
433 return log_error_errno((int) n, "Failed to read core data: %m");
434 if ((size_t) n < size) {
435 log_error("Core data too short.");
440 *ret_size = size + 9;
447 /* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
461 static int compose_open_fds(pid_t pid, char **open_fds) {
462 _cleanup_closedir_ DIR *proc_fd_dir = NULL;
463 _cleanup_close_ int proc_fdinfo_fd = -1;
464 _cleanup_free_ char *buffer = NULL;
465 _cleanup_fclose_ FILE *stream = NULL;
466 const char *fddelim = "", *path;
467 struct dirent *dent = NULL;
472 assert(open_fds != NULL);
474 path = procfs_file_alloca(pid, "fd");
475 proc_fd_dir = opendir(path);
479 proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo", O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
480 if (proc_fdinfo_fd < 0)
483 stream = open_memstream(&buffer, &size);
487 FOREACH_DIRENT(dent, proc_fd_dir, return -errno) {
488 _cleanup_fclose_ FILE *fdinfo = NULL;
489 _cleanup_free_ char *fdname = NULL;
493 r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname);
497 fprintf(stream, "%s%s:%s\n", fddelim, dent->d_name, fdname);
500 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
501 fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
505 fdinfo = fdopen(fd, "re");
506 if (fdinfo == NULL) {
511 FOREACH_LINE(line, fdinfo, break) {
513 if (!endswith(line, "\n"))
531 int main(int argc, char* argv[]) {
533 /* The small core field we allocate on the stack, to keep things simple */
535 *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
536 *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL,
537 *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL,
540 /* The larger ones we allocate on the heap */
542 *core_timestamp = NULL, *core_message = NULL, *coredump_data = NULL, *core_owner_uid = NULL,
543 *core_open_fds = NULL, *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL,
544 *core_proc_cgroup = NULL, *core_environ = NULL;
546 _cleanup_free_ char *exe = NULL, *comm = NULL, *filename = NULL;
547 const char *info[_INFO_LEN];
549 _cleanup_close_ int coredump_fd = -1;
551 struct iovec iovec[26];
554 uid_t uid, owner_uid;
560 /* Make sure we never enter a loop */
561 prctl(PR_SET_DUMPABLE, 0);
563 /* First, log to a safe place, since we don't know what
564 * crashed and it might be journald which we'd rather not log
566 log_set_target(LOG_TARGET_KMSG);
569 if (argc < INFO_COMM + 1) {
570 log_error("Not enough arguments passed from kernel (%d, expected %d).",
571 argc - 1, INFO_COMM + 1 - 1);
576 /* Ignore all parse errors */
579 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
580 log_debug("Selected compression %s.", yes_no(arg_compress));
582 r = parse_uid(argv[INFO_UID + 1], &uid);
584 log_error("Failed to parse UID.");
588 r = parse_pid(argv[INFO_PID + 1], &pid);
590 log_error("Failed to parse PID.");
594 r = parse_gid(argv[INFO_GID + 1], &gid);
596 log_error("Failed to parse GID.");
600 if (get_process_comm(pid, &comm) < 0) {
601 log_warning("Failed to get COMM, falling back to the command line.");
602 comm = strv_join(argv + INFO_COMM + 1, " ");
605 if (get_process_exe(pid, &exe) < 0)
606 log_warning("Failed to get EXE.");
608 info[INFO_PID] = argv[INFO_PID + 1];
609 info[INFO_UID] = argv[INFO_UID + 1];
610 info[INFO_GID] = argv[INFO_GID + 1];
611 info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
612 info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
613 info[INFO_COMM] = comm;
614 info[INFO_EXE] = exe;
616 if (cg_pid_get_unit(pid, &t) >= 0) {
618 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
621 /* If we are journald, we cut things short,
622 * don't write to the journal, but still
623 * create a coredump. */
625 if (arg_storage != COREDUMP_STORAGE_NONE)
626 arg_storage = COREDUMP_STORAGE_EXTERNAL;
628 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
632 r = maybe_remove_external_coredump(filename, coredump_size);
636 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
640 core_unit = strappenda("COREDUMP_UNIT=", t);
643 } else if (cg_pid_get_user_unit(pid, &t) >= 0) {
644 core_unit = strappenda("COREDUMP_USER_UNIT=", t);
649 IOVEC_SET_STRING(iovec[j++], core_unit);
651 /* OK, now we know it's not the journal, hence we can make use
653 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
656 core_pid = strappenda("COREDUMP_PID=", info[INFO_PID]);
657 IOVEC_SET_STRING(iovec[j++], core_pid);
659 core_uid = strappenda("COREDUMP_UID=", info[INFO_UID]);
660 IOVEC_SET_STRING(iovec[j++], core_uid);
662 core_gid = strappenda("COREDUMP_GID=", info[INFO_GID]);
663 IOVEC_SET_STRING(iovec[j++], core_gid);
665 core_signal = strappenda("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
666 IOVEC_SET_STRING(iovec[j++], core_signal);
668 if (sd_pid_get_session(pid, &t) >= 0) {
669 core_session = strappenda("COREDUMP_SESSION=", t);
672 IOVEC_SET_STRING(iovec[j++], core_session);
675 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
676 r = asprintf(&core_owner_uid,
677 "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
679 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
682 if (sd_pid_get_slice(pid, &t) >= 0) {
683 core_slice = strappenda("COREDUMP_SLICE=", t);
686 IOVEC_SET_STRING(iovec[j++], core_slice);
690 core_comm = strappenda("COREDUMP_COMM=", comm);
691 IOVEC_SET_STRING(iovec[j++], core_comm);
695 core_exe = strappenda("COREDUMP_EXE=", exe);
696 IOVEC_SET_STRING(iovec[j++], core_exe);
699 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
700 core_cmdline = strappenda("COREDUMP_CMDLINE=", t);
703 IOVEC_SET_STRING(iovec[j++], core_cmdline);
706 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
707 core_cgroup = strappenda("COREDUMP_CGROUP=", t);
710 IOVEC_SET_STRING(iovec[j++], core_cgroup);
713 if (compose_open_fds(pid, &t) >= 0) {
714 core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
718 IOVEC_SET_STRING(iovec[j++], core_open_fds);
721 p = procfs_file_alloca(pid, "status");
722 if (read_full_file(p, &t, NULL) >= 0) {
723 core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
726 if (core_proc_status)
727 IOVEC_SET_STRING(iovec[j++], core_proc_status);
730 p = procfs_file_alloca(pid, "maps");
731 if (read_full_file(p, &t, NULL) >= 0) {
732 core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
736 IOVEC_SET_STRING(iovec[j++], core_proc_maps);
739 p = procfs_file_alloca(pid, "limits");
740 if (read_full_file(p, &t, NULL) >= 0) {
741 core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
744 if (core_proc_limits)
745 IOVEC_SET_STRING(iovec[j++], core_proc_limits);
748 p = procfs_file_alloca(pid, "cgroup");
749 if (read_full_file(p, &t, NULL) >=0) {
750 core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
753 if (core_proc_cgroup)
754 IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
757 if (get_process_cwd(pid, &t) >= 0) {
758 core_cwd = strappenda("COREDUMP_CWD=", t);
761 IOVEC_SET_STRING(iovec[j++], core_cwd);
764 if (get_process_root(pid, &t) >= 0) {
765 core_root = strappenda("COREDUMP_ROOT=", t);
768 IOVEC_SET_STRING(iovec[j++], core_root);
771 if (get_process_environ(pid, &t) >= 0) {
772 core_environ = strappend("COREDUMP_ENVIRON=", t);
776 IOVEC_SET_STRING(iovec[j++], core_environ);
779 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
781 IOVEC_SET_STRING(iovec[j++], core_timestamp);
783 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
784 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
786 /* Vacuum before we write anything again */
787 coredump_vacuum(-1, arg_keep_free, arg_max_use);
789 /* Always stream the coredump to disk, if that's possible */
790 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
792 /* skip whole core dumping part */
795 /* If we don't want to keep the coredump on disk, remove it
796 * now, as later on we will lack the privileges for
797 * it. However, we keep the fd to it, so that we can still
798 * process it and log it. */
799 r = maybe_remove_external_coredump(filename, coredump_size);
803 const char *coredump_filename;
805 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
806 IOVEC_SET_STRING(iovec[j++], coredump_filename);
809 /* Vacuum again, but exclude the coredump we just created */
810 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
812 /* Now, let's drop privileges to become the user who owns the
813 * segfaulted process and allocate the coredump memory under
814 * the user's uid. This also ensures that the credentials
815 * journald will see are the ones of the coredumping user,
816 * thus making sure the user gets access to the core dump. */
817 if (setresgid(gid, gid, gid) < 0 ||
818 setresuid(uid, uid, uid) < 0) {
819 log_error_errno(errno, "Failed to drop privileges: %m");
825 /* Try to get a strack trace if we can */
826 if (coredump_size <= arg_process_size_max) {
827 _cleanup_free_ char *stacktrace = NULL;
829 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
831 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
832 else if (r == -EINVAL)
833 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
835 log_warning_errno(r, "Failed to generate stack trace: %m");
841 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
843 IOVEC_SET_STRING(iovec[j++], core_message);
845 /* Optionally store the entire coredump in the journal */
846 if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
847 coredump_size <= (off_t) arg_journal_size_max) {
850 /* Store the coredump itself in the journal */
852 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
854 iovec[j].iov_base = coredump_data;
855 iovec[j].iov_len = sz;
860 r = sd_journal_sendv(iovec, j);
862 log_error_errno(r, "Failed to log coredump: %m");
865 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;