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_many("/etc/systemd/coredump.conf",
124 CONF_DIRS_NULSTR("systemd/coredump.conf"),
126 config_item_table_lookup, items,
130 static int fix_acl(int fd, uid_t uid) {
133 _cleanup_(acl_freep) acl_t acl = NULL;
135 acl_permset_t permset;
139 if (uid <= SYSTEM_UID_MAX)
142 /* Make sure normal users can read (but not write or delete)
143 * their own coredumps */
145 acl = acl_get_fd(fd);
147 return log_error_errno(errno, "Failed to get ACL: %m");
149 if (acl_create_entry(&acl, &entry) < 0 ||
150 acl_set_tag_type(entry, ACL_USER) < 0 ||
151 acl_set_qualifier(entry, &uid) < 0) {
152 log_error_errno(errno, "Failed to patch ACL: %m");
156 if (acl_get_permset(entry, &permset) < 0 ||
157 acl_add_perm(permset, ACL_READ) < 0 ||
158 calc_acl_mask_if_needed(&acl) < 0) {
159 log_warning_errno(errno, "Failed to patch ACL: %m");
163 if (acl_set_fd(fd, acl) < 0)
164 return log_error_errno(errno, "Failed to apply ACL: %m");
170 static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
172 static const char * const xattrs[_INFO_LEN] = {
173 [INFO_PID] = "user.coredump.pid",
174 [INFO_UID] = "user.coredump.uid",
175 [INFO_GID] = "user.coredump.gid",
176 [INFO_SIGNAL] = "user.coredump.signal",
177 [INFO_TIMESTAMP] = "user.coredump.timestamp",
178 [INFO_COMM] = "user.coredump.comm",
179 [INFO_EXE] = "user.coredump.exe",
187 /* Attach some metadata to coredumps via extended
188 * attributes. Just because we can. */
190 for (i = 0; i < _INFO_LEN; i++) {
193 if (isempty(info[i]) || !xattrs[i])
196 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
204 #define filename_escape(s) xescape((s), "./ ")
206 static int fix_permissions(
208 const char *filename,
210 const char *info[_INFO_LEN],
218 /* Ignore errors on these */
224 return log_error_errno(errno, "Failed to sync coredump %s: %m", filename);
226 if (rename(filename, target) < 0)
227 return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
232 static int maybe_remove_external_coredump(const char *filename, off_t size) {
234 /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
236 if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
237 size <= arg_external_size_max)
243 if (unlink(filename) < 0 && errno != ENOENT)
244 return log_error_errno(errno, "Failed to unlink %s: %m", filename);
249 static int make_filename(const char *info[_INFO_LEN], char **ret) {
250 _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
256 c = filename_escape(info[INFO_COMM]);
260 u = filename_escape(info[INFO_UID]);
264 r = sd_id128_get_boot(&boot);
268 p = filename_escape(info[INFO_PID]);
272 t = filename_escape(info[INFO_TIMESTAMP]);
277 "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
280 SD_ID128_FORMAT_VAL(boot),
288 static int save_external_coredump(
289 const char *info[_INFO_LEN],
295 _cleanup_free_ char *fn = NULL, *tmp = NULL;
296 _cleanup_close_ int fd = -1;
301 assert(ret_filename);
305 r = make_filename(info, &fn);
307 return log_error_errno(r, "Failed to determine coredump file name: %m");
309 r = tempfn_random(fn, &tmp);
311 return log_error_errno(r, "Failed to determine temporary file name: %m");
313 mkdir_p_label("/var/lib/systemd/coredump", 0755);
315 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
317 return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
319 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max, false);
321 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
323 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
324 log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
327 log_error_errno(r, "Failed to dump coredump to file: %m");
331 if (fstat(fd, &st) < 0) {
332 log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
336 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
337 log_error_errno(errno, "Failed to seek on %s: %m", tmp);
341 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
342 /* If we will remove the coredump anyway, do not compress. */
343 if (maybe_remove_external_coredump(NULL, st.st_size) == 0
346 _cleanup_free_ char *fn_compressed = NULL, *tmp_compressed = NULL;
347 _cleanup_close_ int fd_compressed = -1;
349 fn_compressed = strappend(fn, COMPRESSED_EXT);
350 if (!fn_compressed) {
355 r = tempfn_random(fn_compressed, &tmp_compressed);
357 log_error_errno(r, "Failed to determine temporary file name for %s: %m", fn_compressed);
361 fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
362 if (fd_compressed < 0) {
363 log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
367 r = compress_stream(fd, fd_compressed, -1);
369 log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
370 goto fail_compressed;
373 r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid);
375 goto fail_compressed;
377 /* OK, this worked, we can get rid of the uncompressed version now */
380 *ret_filename = fn_compressed; /* compressed */
381 *ret_fd = fd; /* uncompressed */
382 *ret_size = st.st_size; /* uncompressed */
384 fn_compressed = NULL;
390 unlink_noerrno(tmp_compressed);
395 r = fix_permissions(fd, tmp, fn, info, uid);
401 *ret_size = st.st_size;
413 static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
414 _cleanup_free_ char *field = NULL;
421 if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
422 return log_warning_errno(errno, "Failed to seek: %m");
424 field = malloc(9 + size);
426 log_warning("Failed to allocate memory for coredump, coredump will not be stored.");
430 memcpy(field, "COREDUMP=", 9);
432 n = read(fd, field + 9, size);
434 return log_error_errno((int) n, "Failed to read core data: %m");
435 if ((size_t) n < size) {
436 log_error("Core data too short.");
441 *ret_size = size + 9;
448 /* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
462 static int compose_open_fds(pid_t pid, char **open_fds) {
463 _cleanup_closedir_ DIR *proc_fd_dir = NULL;
464 _cleanup_close_ int proc_fdinfo_fd = -1;
465 _cleanup_free_ char *buffer = NULL;
466 _cleanup_fclose_ FILE *stream = NULL;
467 const char *fddelim = "", *path;
468 struct dirent *dent = NULL;
473 assert(open_fds != NULL);
475 path = procfs_file_alloca(pid, "fd");
476 proc_fd_dir = opendir(path);
480 proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo", O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
481 if (proc_fdinfo_fd < 0)
484 stream = open_memstream(&buffer, &size);
488 FOREACH_DIRENT(dent, proc_fd_dir, return -errno) {
489 _cleanup_fclose_ FILE *fdinfo = NULL;
490 _cleanup_free_ char *fdname = NULL;
494 r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname);
498 fprintf(stream, "%s%s:%s\n", fddelim, dent->d_name, fdname);
501 /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
502 fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
506 fdinfo = fdopen(fd, "re");
507 if (fdinfo == NULL) {
512 FOREACH_LINE(line, fdinfo, break) {
514 if (!endswith(line, "\n"))
532 int main(int argc, char* argv[]) {
534 /* The small core field we allocate on the stack, to keep things simple */
536 *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
537 *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL,
538 *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL,
541 /* The larger ones we allocate on the heap */
543 *core_timestamp = NULL, *core_message = NULL, *coredump_data = NULL, *core_owner_uid = NULL,
544 *core_open_fds = NULL, *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL,
545 *core_proc_cgroup = NULL, *core_environ = NULL;
547 _cleanup_free_ char *exe = NULL, *comm = NULL, *filename = NULL;
548 const char *info[_INFO_LEN];
550 _cleanup_close_ int coredump_fd = -1;
552 struct iovec iovec[26];
555 uid_t uid, owner_uid;
561 /* Make sure we never enter a loop */
562 prctl(PR_SET_DUMPABLE, 0);
564 /* First, log to a safe place, since we don't know what
565 * crashed and it might be journald which we'd rather not log
567 log_set_target(LOG_TARGET_KMSG);
570 if (argc < INFO_COMM + 1) {
571 log_error("Not enough arguments passed from kernel (%d, expected %d).",
572 argc - 1, INFO_COMM + 1 - 1);
577 /* Ignore all parse errors */
580 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
581 log_debug("Selected compression %s.", yes_no(arg_compress));
583 r = parse_uid(argv[INFO_UID + 1], &uid);
585 log_error("Failed to parse UID.");
589 r = parse_pid(argv[INFO_PID + 1], &pid);
591 log_error("Failed to parse PID.");
595 r = parse_gid(argv[INFO_GID + 1], &gid);
597 log_error("Failed to parse GID.");
601 if (get_process_comm(pid, &comm) < 0) {
602 log_warning("Failed to get COMM, falling back to the command line.");
603 comm = strv_join(argv + INFO_COMM + 1, " ");
606 if (get_process_exe(pid, &exe) < 0)
607 log_warning("Failed to get EXE.");
609 info[INFO_PID] = argv[INFO_PID + 1];
610 info[INFO_UID] = argv[INFO_UID + 1];
611 info[INFO_GID] = argv[INFO_GID + 1];
612 info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
613 info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
614 info[INFO_COMM] = comm;
615 info[INFO_EXE] = exe;
617 if (cg_pid_get_unit(pid, &t) >= 0) {
619 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
622 /* If we are journald, we cut things short,
623 * don't write to the journal, but still
624 * create a coredump. */
626 if (arg_storage != COREDUMP_STORAGE_NONE)
627 arg_storage = COREDUMP_STORAGE_EXTERNAL;
629 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
633 r = maybe_remove_external_coredump(filename, coredump_size);
637 log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
641 core_unit = strappenda("COREDUMP_UNIT=", t);
644 } else if (cg_pid_get_user_unit(pid, &t) >= 0) {
645 core_unit = strappenda("COREDUMP_USER_UNIT=", t);
650 IOVEC_SET_STRING(iovec[j++], core_unit);
652 /* OK, now we know it's not the journal, hence we can make use
654 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
657 core_pid = strappenda("COREDUMP_PID=", info[INFO_PID]);
658 IOVEC_SET_STRING(iovec[j++], core_pid);
660 core_uid = strappenda("COREDUMP_UID=", info[INFO_UID]);
661 IOVEC_SET_STRING(iovec[j++], core_uid);
663 core_gid = strappenda("COREDUMP_GID=", info[INFO_GID]);
664 IOVEC_SET_STRING(iovec[j++], core_gid);
666 core_signal = strappenda("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
667 IOVEC_SET_STRING(iovec[j++], core_signal);
669 if (sd_pid_get_session(pid, &t) >= 0) {
670 core_session = strappenda("COREDUMP_SESSION=", t);
673 IOVEC_SET_STRING(iovec[j++], core_session);
676 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
677 r = asprintf(&core_owner_uid,
678 "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
680 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
683 if (sd_pid_get_slice(pid, &t) >= 0) {
684 core_slice = strappenda("COREDUMP_SLICE=", t);
687 IOVEC_SET_STRING(iovec[j++], core_slice);
691 core_comm = strappenda("COREDUMP_COMM=", comm);
692 IOVEC_SET_STRING(iovec[j++], core_comm);
696 core_exe = strappenda("COREDUMP_EXE=", exe);
697 IOVEC_SET_STRING(iovec[j++], core_exe);
700 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
701 core_cmdline = strappenda("COREDUMP_CMDLINE=", t);
704 IOVEC_SET_STRING(iovec[j++], core_cmdline);
707 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
708 core_cgroup = strappenda("COREDUMP_CGROUP=", t);
711 IOVEC_SET_STRING(iovec[j++], core_cgroup);
714 if (compose_open_fds(pid, &t) >= 0) {
715 core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
719 IOVEC_SET_STRING(iovec[j++], core_open_fds);
722 p = procfs_file_alloca(pid, "status");
723 if (read_full_file(p, &t, NULL) >= 0) {
724 core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
727 if (core_proc_status)
728 IOVEC_SET_STRING(iovec[j++], core_proc_status);
731 p = procfs_file_alloca(pid, "maps");
732 if (read_full_file(p, &t, NULL) >= 0) {
733 core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
737 IOVEC_SET_STRING(iovec[j++], core_proc_maps);
740 p = procfs_file_alloca(pid, "limits");
741 if (read_full_file(p, &t, NULL) >= 0) {
742 core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
745 if (core_proc_limits)
746 IOVEC_SET_STRING(iovec[j++], core_proc_limits);
749 p = procfs_file_alloca(pid, "cgroup");
750 if (read_full_file(p, &t, NULL) >=0) {
751 core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
754 if (core_proc_cgroup)
755 IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
758 if (get_process_cwd(pid, &t) >= 0) {
759 core_cwd = strappenda("COREDUMP_CWD=", t);
762 IOVEC_SET_STRING(iovec[j++], core_cwd);
765 if (get_process_root(pid, &t) >= 0) {
766 core_root = strappenda("COREDUMP_ROOT=", t);
769 IOVEC_SET_STRING(iovec[j++], core_root);
772 if (get_process_environ(pid, &t) >= 0) {
773 core_environ = strappend("COREDUMP_ENVIRON=", t);
777 IOVEC_SET_STRING(iovec[j++], core_environ);
780 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
782 IOVEC_SET_STRING(iovec[j++], core_timestamp);
784 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
785 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
787 /* Vacuum before we write anything again */
788 coredump_vacuum(-1, arg_keep_free, arg_max_use);
790 /* Always stream the coredump to disk, if that's possible */
791 r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
793 /* skip whole core dumping part */
796 /* If we don't want to keep the coredump on disk, remove it
797 * now, as later on we will lack the privileges for
798 * it. However, we keep the fd to it, so that we can still
799 * process it and log it. */
800 r = maybe_remove_external_coredump(filename, coredump_size);
804 const char *coredump_filename;
806 coredump_filename = strappenda("COREDUMP_FILENAME=", filename);
807 IOVEC_SET_STRING(iovec[j++], coredump_filename);
810 /* Vacuum again, but exclude the coredump we just created */
811 coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
813 /* Now, let's drop privileges to become the user who owns the
814 * segfaulted process and allocate the coredump memory under
815 * the user's uid. This also ensures that the credentials
816 * journald will see are the ones of the coredumping user,
817 * thus making sure the user gets access to the core dump. */
818 if (setresgid(gid, gid, gid) < 0 ||
819 setresuid(uid, uid, uid) < 0) {
820 log_error_errno(errno, "Failed to drop privileges: %m");
826 /* Try to get a strack trace if we can */
827 if (coredump_size <= arg_process_size_max) {
828 _cleanup_free_ char *stacktrace = NULL;
830 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
832 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
833 else if (r == -EINVAL)
834 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
836 log_warning_errno(r, "Failed to generate stack trace: %m");
842 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
844 IOVEC_SET_STRING(iovec[j++], core_message);
846 /* Optionally store the entire coredump in the journal */
847 if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
848 coredump_size <= (off_t) arg_journal_size_max) {
851 /* Store the coredump itself in the journal */
853 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
855 iovec[j].iov_base = coredump_data;
856 iovec[j].iov_len = sz;
861 r = sd_journal_sendv(iovec, j);
863 log_error_errno(r, "Failed to log coredump: %m");
866 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;