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>
29 #include <systemd/sd-journal.h>
30 #include <systemd/sd-login.h>
38 #include "cgroup-util.h"
39 #include "journald-native.h"
40 #include "conf-parser.h"
42 #include "stacktrace.h"
43 #include "path-util.h"
50 /* The maximum size up to which we process coredumps */
51 #define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
53 /* The maximum size up to which we leave the coredump around on
55 #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
57 /* The maximum size up to which we store the coredump in the
59 #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
61 /* Make sure to not make this larger than the maximum journal entry
62 * size. See ENTRY_SIZE_MAX in journald-native.c. */
63 assert_cc(JOURNAL_SIZE_MAX <= ENTRY_SIZE_MAX);
76 typedef enum CoredumpStorage {
77 COREDUMP_STORAGE_NONE,
78 COREDUMP_STORAGE_EXTERNAL,
79 COREDUMP_STORAGE_JOURNAL,
80 COREDUMP_STORAGE_BOTH,
81 _COREDUMP_STORAGE_MAX,
82 _COREDUMP_STORAGE_INVALID = -1
85 static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
86 static off_t arg_process_size_max = PROCESS_SIZE_MAX;
87 static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
88 static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
90 static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
91 [COREDUMP_STORAGE_NONE] = "none",
92 [COREDUMP_STORAGE_EXTERNAL] = "external",
93 [COREDUMP_STORAGE_JOURNAL] = "journal",
94 [COREDUMP_STORAGE_BOTH] = "both",
97 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
98 static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
100 static int parse_config(void) {
102 static const ConfigTableItem items[] = {
103 { "Coredump", "ProcessSizeMax", config_parse_iec_off, 0, &arg_process_size_max },
104 { "Coredump", "ExternalSizeMax", config_parse_iec_off, 0, &arg_external_size_max },
105 { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
106 { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
112 "/etc/systemd/coredump.conf",
115 config_item_table_lookup,
122 static int fix_acl(int fd, uid_t uid) {
125 _cleanup_(acl_freep) acl_t acl = NULL;
127 acl_permset_t permset;
129 if (uid <= SYSTEM_UID_MAX)
132 /* Make sure normal users can read (but not write or delete)
133 * their own coredumps */
135 acl = acl_get_fd(fd);
137 log_error("Failed to get ACL: %m");
141 if (acl_create_entry(&acl, &entry) < 0 ||
142 acl_set_tag_type(entry, ACL_USER) < 0 ||
143 acl_set_qualifier(entry, &uid) < 0) {
144 log_error("Failed to patch ACL: %m");
148 if (acl_get_permset(entry, &permset) < 0 ||
149 acl_add_perm(permset, ACL_READ) < 0 ||
150 calc_acl_mask_if_needed(&acl) < 0) {
151 log_warning("Failed to patch ACL: %m");
155 if (acl_set_fd(fd, acl) < 0) {
156 log_error("Failed to apply ACL: %m");
164 static int fix_xattr(int fd, const char *info[_INFO_LEN]) {
166 static const char * const xattrs[_INFO_LEN] = {
167 [INFO_PID] = "user.coredump.pid",
168 [INFO_UID] = "user.coredump.uid",
169 [INFO_GID] = "user.coredump.gid",
170 [INFO_SIGNAL] = "user.coredump.signal",
171 [INFO_TIMESTAMP] = "user.coredump.timestamp",
172 [INFO_COMM] = "user.coredump.comm",
173 [INFO_EXE] = "user.coredump.exe",
179 /* Attach some metadata to coredumps via extended
180 * attributes. Just because we can. */
182 for (i = 0; i < _INFO_LEN; i++) {
185 if (isempty(info[i]) || !xattrs[i])
188 k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE);
196 #define filename_escape(s) xescape((s), "./ ")
198 static int save_external_coredump(const char *info[_INFO_LEN],
204 _cleanup_free_ char *p = NULL, *t = NULL, *c = NULL, *fn = NULL, *tmp = NULL;
205 _cleanup_close_ int fd = -1;
211 assert(ret_filename);
215 c = filename_escape(info[INFO_COMM]);
219 p = filename_escape(info[INFO_PID]);
223 t = filename_escape(info[INFO_TIMESTAMP]);
227 r = sd_id128_get_boot(&boot);
229 log_error("Failed to determine boot ID: %s", strerror(-r));
234 "/var/lib/systemd/coredump/core.%s." SD_ID128_FORMAT_STR ".%s.%s000000",
236 SD_ID128_FORMAT_VAL(boot),
242 tmp = tempfn_random(fn);
246 mkdir_p_label("/var/lib/systemd/coredump", 0755);
248 fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
250 log_error("Failed to create coredump file: %m");
254 r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
256 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.",
257 info[INFO_PID], info[INFO_COMM]);
259 } else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
260 log_error("Not enough disk space for coredump of %s (%s), refusing.",
261 info[INFO_PID], info[INFO_COMM]);
264 log_error("Failed to dump coredump to file: %s", strerror(-r));
268 /* Ignore errors on these */
274 log_error("Failed to sync coredump %s: %m", tmp);
279 if (fstat(fd, &st) < 0) {
280 log_error("Failed to fstat coredump %s: %m", tmp);
285 if (rename(tmp, fn) < 0) {
286 log_error("Failed to rename coredump %s -> %s: %m", tmp, fn);
293 *ret_size = st.st_size;
305 static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_size) {
306 _cleanup_free_ char *field = NULL;
313 if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
314 log_warning("Failed to seek: %m");
318 field = malloc(9 + size);
320 log_warning("Failed to allocate memory fore coredump, coredump will not be stored.");
324 memcpy(field, "COREDUMP=", 9);
326 n = read(fd, field + 9, size);
328 log_error("Failed to read core data: %s", strerror(-n));
331 if ((size_t) n < size) {
332 log_error("Core data too short.");
337 *ret_size = size + 9;
344 static int maybe_remove_external_coredump(const char *filename, off_t size) {
349 if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
350 size <= arg_external_size_max)
353 if (unlink(filename) < 0) {
354 log_error("Failed to unlink %s: %m", filename);
361 int main(int argc, char* argv[]) {
363 _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
364 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
365 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
366 *coredump_filename = NULL, *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
367 *exe = NULL, *comm = NULL;
368 const char *info[_INFO_LEN];
370 _cleanup_close_ int coredump_fd = -1;
372 struct iovec iovec[17];
375 uid_t uid, owner_uid;
380 /* Make sure we never enter a loop */
381 prctl(PR_SET_DUMPABLE, 0);
383 /* First, log to a safe place, since we don't know what
384 * crashed and it might be journald which we'd rather not log
386 log_set_target(LOG_TARGET_KMSG);
389 if (argc < INFO_COMM + 1) {
390 log_error("Not enough arguments passed from kernel (%d, expected %d).",
391 argc - 1, INFO_COMM + 1 - 1);
396 /* Ignore all parse errors */
398 log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
400 r = parse_uid(argv[INFO_UID + 1], &uid);
402 log_error("Failed to parse UID.");
406 r = parse_pid(argv[INFO_PID + 1], &pid);
408 log_error("Failed to parse PID.");
412 r = parse_gid(argv[INFO_GID + 1], &gid);
414 log_error("Failed to parse GID.");
418 if (get_process_comm(pid, &comm) < 0) {
419 log_warning("Failed to get COMM, falling back to the commandline.");
420 comm = strv_join(argv + INFO_COMM + 1, " ");
423 if (get_process_exe(pid, &exe) < 0)
424 log_warning("Failed to get EXE.");
426 info[INFO_PID] = argv[INFO_PID + 1];
427 info[INFO_UID] = argv[INFO_UID + 1];
428 info[INFO_GID] = argv[INFO_GID + 1];
429 info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
430 info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
431 info[INFO_COMM] = comm;
432 info[INFO_EXE] = exe;
434 if (cg_pid_get_unit(pid, &t) >= 0) {
436 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
438 /* If we are journald, we cut things short,
439 * don't write to the journal, but still
440 * create a coredump. */
442 if (arg_storage != COREDUMP_STORAGE_NONE)
443 arg_storage = COREDUMP_STORAGE_EXTERNAL;
445 r = save_external_coredump(info, uid, &coredump_filename, &coredump_fd, &coredump_size);
449 r = maybe_remove_external_coredump(coredump_filename, coredump_size);
453 log_info("Detected coredump of the journal daemon itself, diverted to %s.", coredump_filename);
457 core_unit = strappend("COREDUMP_UNIT=", t);
458 } else if (cg_pid_get_user_unit(pid, &t) >= 0)
459 core_unit = strappend("COREDUMP_USER_UNIT=", t);
462 IOVEC_SET_STRING(iovec[j++], core_unit);
464 /* OK, now we know it's not the journal, hence we can make use
466 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
469 core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
471 IOVEC_SET_STRING(iovec[j++], core_pid);
473 core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
475 IOVEC_SET_STRING(iovec[j++], core_uid);
477 core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
479 IOVEC_SET_STRING(iovec[j++], core_gid);
481 core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
483 IOVEC_SET_STRING(iovec[j++], core_signal);
485 if (sd_pid_get_session(pid, &t) >= 0) {
486 core_session = strappend("COREDUMP_SESSION=", t);
490 IOVEC_SET_STRING(iovec[j++], core_session);
493 if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
494 asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
497 IOVEC_SET_STRING(iovec[j++], core_owner_uid);
500 if (sd_pid_get_slice(pid, &t) >= 0) {
501 core_slice = strappend("COREDUMP_SLICE=", t);
505 IOVEC_SET_STRING(iovec[j++], core_slice);
509 core_comm = strappend("COREDUMP_COMM=", comm);
511 IOVEC_SET_STRING(iovec[j++], core_comm);
515 core_exe = strappend("COREDUMP_EXE=", exe);
517 IOVEC_SET_STRING(iovec[j++], core_exe);
520 if (get_process_cmdline(pid, 0, false, &t) >= 0) {
521 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
525 IOVEC_SET_STRING(iovec[j++], core_cmdline);
528 if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
529 core_cgroup = strappend("COREDUMP_CGROUP=", t);
533 IOVEC_SET_STRING(iovec[j++], core_cgroup);
536 core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
538 IOVEC_SET_STRING(iovec[j++], core_timestamp);
540 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
541 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
543 /* Always stream the coredump to disk, if that's possible */
544 r = save_external_coredump(info, uid, &coredump_filename, &coredump_fd, &coredump_size);
546 /* skip whole core dumping part */
549 /* If we don't want to keep the coredump on disk, remove it
550 * now, as later on we will lack the privileges for
551 * it. However, we keep the fd to it, so that we can still
552 * process it and log it. */
553 r = maybe_remove_external_coredump(coredump_filename, coredump_size);
557 /* Now, let's drop privileges to become the user who owns the
558 * segfaulted process and allocate the coredump memory under
559 * his uid. This also ensures that the credentials journald
560 * will see are the ones of the coredumping user, thus making
561 * sure the user himself gets access to the core dump. */
562 if (setresgid(gid, gid, gid) < 0 ||
563 setresuid(uid, uid, uid) < 0) {
564 log_error("Failed to drop privileges: %m");
570 /* Try to get a strack trace if we can */
571 if (coredump_size <= arg_process_size_max) {
572 _cleanup_free_ char *stacktrace = NULL;
574 r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
576 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
578 log_warning("Failed to generate stack trace: %s", strerror(-r));
584 core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
586 IOVEC_SET_STRING(iovec[j++], core_message);
588 /* Optionally store the entire coredump in the journal */
589 if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
590 coredump_size <= (off_t) arg_journal_size_max) {
593 /* Store the coredump itself in the journal */
595 r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
597 iovec[j].iov_base = coredump_data;
598 iovec[j].iov_len = sz;
603 r = sd_journal_sendv(iovec, j);
605 log_error("Failed to log coredump: %s", strerror(-r));
608 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;