#include <errno.h>
#include <stdio.h>
-#include <stdio_ext.h>
#include <sys/prctl.h>
#include <sys/xattr.h>
#include <unistd.h>
#include "journal-importer.h"
#include "log.h"
#include "macro.h"
+#include "main-func.h"
+#include "memory-util.h"
#include "missing.h"
#include "mkdir.h"
#include "parse-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
+#include "tmpfile-util.h"
#include "user-util.h"
-#include "util.h"
/* The maximum size up to which we process coredumps */
#define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU))
#define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX
/* The maximum size up to which we store the coredump in the journal */
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
#define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU))
+#else
+/* oss-fuzz limits memory usage. */
+#define JOURNAL_SIZE_MAX ((size_t) (10LU*1024LU*1024LU))
+#endif
/* Make sure to not make this larger than the maximum journal entry
- * size. See DATA_SIZE_MAX in journald-native.c. */
+ * size. See DATA_SIZE_MAX in journal-importer.h. */
assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX);
enum {
CONFIG_PARSE_WARN, NULL);
}
-static inline uint64_t storage_size_max(void) {
+static uint64_t storage_size_max(void) {
if (arg_storage == COREDUMP_STORAGE_EXTERNAL)
return arg_external_size_max;
if (arg_storage == COREDUMP_STORAGE_JOURNAL)
#define filename_escape(s) xescape((s), "./ ")
-static inline const char *coredump_tmpfile_name(const char *s) {
+static const char *coredump_tmpfile_name(const char *s) {
return s ? s : "(unnamed temporary file)";
}
r = safe_atou64(context[CONTEXT_RLIMIT], &rlimit);
if (r < 0)
- return log_error_errno(r, "Failed to parse resource limit: %s", context[CONTEXT_RLIMIT]);
+ return log_error_errno(r, "Failed to parse resource limit '%s': %m", context[CONTEXT_RLIMIT]);
if (rlimit < page_size()) {
/* Is coredumping disabled? Then don't bother saving/processing the coredump.
* Anything below PAGE_SIZE cannot give a readable coredump (the kernel uses
* ELF_EXEC_PAGESIZE which is not easily accessible, but is usually the same as PAGE_SIZE. */
- log_info("Resource limits disable core dumping for process %s (%s).",
- context[CONTEXT_PID], context[CONTEXT_COMM]);
- return -EBADSLT;
+ return log_info_errno(SYNTHETIC_ERRNO(EBADSLT),
+ "Resource limits disable core dumping for process %s (%s).",
+ context[CONTEXT_PID], context[CONTEXT_COMM]);
}
process_limit = MAX(arg_process_size_max, storage_size_max());
- if (process_limit == 0) {
- log_debug("Limits for coredump processing and storage are both 0, not dumping core.");
- return -EBADSLT;
- }
+ if (process_limit == 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(EBADSLT),
+ "Limits for coredump processing and storage are both 0, not dumping core.");
/* Never store more than the process configured, or than we actually shall keep or process */
max_size = MIN(rlimit, process_limit);
if (r < 0)
return log_error_errno(r, "Failed to determine coredump file name: %m");
- mkdir_p_label("/var/lib/systemd/coredump", 0755);
+ (void) mkdir_p_label("/var/lib/systemd/coredump", 0755);
fd = open_tmpfile_linkable(fn, O_RDWR|O_CLOEXEC, &tmp);
if (fd < 0)
n = read(fd, field + 9, size);
if (n < 0)
return log_error_errno((int) n, "Failed to read core data: %m");
- if ((size_t) n < size) {
- log_error("Core data too short.");
- return -EIO;
- }
+ if ((size_t) n < size)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+ "Core data too short.");
*ret = TAKE_PTR(field);
*ret_size = size + 9;
if (proc_fdinfo_fd < 0)
return -errno;
- stream = open_memstream(&buffer, &size);
+ stream = open_memstream_unlocked(&buffer, &size);
if (!stream)
return -ENOMEM;
- (void) __fsetlocking(stream, FSETLOCKING_BYCALLER);
-
FOREACH_DIRENT(dent, proc_fd_dir, return -errno) {
_cleanup_fclose_ FILE *fdinfo = NULL;
_cleanup_free_ char *fdname = NULL;
if (fd < 0)
continue;
- fdinfo = fdopen(fd, "re");
+ fdinfo = fdopen(fd, "r");
if (!fdinfo) {
safe_close(fd);
continue;
if (r < 0)
return r;
- r = get_process_cmdline(container_pid, 0, false, cmdline);
+ r = get_process_cmdline(container_pid, SIZE_MAX, 0, cmdline);
if (r < 0)
return r;
return log_error_errno(r, "Failed to drop privileges: %m");
#if HAVE_ELFUTILS
- /* Try to get a strack trace if we can */
+ /* Try to get a stack trace if we can */
if (coredump_size <= arg_process_size_max) {
_cleanup_free_ char *stacktrace = NULL;
core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID],
" (", context[CONTEXT_COMM], ") of user ",
context[CONTEXT_UID], " dumped core.",
- journald_crash ? "\nCoredump diverted to " : NULL,
- journald_crash ? filename : NULL);
+ journald_crash && filename ? "\nCoredump diverted to " : NULL,
+ journald_crash && filename ? filename : NULL);
if (!core_message)
return log_oom();
if (journald_crash) {
- /* We cannot log to the journal, so just print the MESSAGE.
+ /* We cannot log to the journal, so just print the message.
* The target was set previously to something safe. */
- log_dispatch(LOG_ERR, 0, core_message);
+ assert(startswith(core_message, "MESSAGE="));
+ log_dispatch(LOG_ERR, 0, core_message + strlen("MESSAGE="));
return 0;
}
assert(fd >= 0);
- log_set_target(LOG_TARGET_AUTO);
- log_parse_environment();
- log_open();
+ log_setup_service();
log_debug("Processing coredump received on stdin...");
* (truncated) copy of what we want to send, and the second one
* contains the trailing dots. */
copy[0] = iovec[i];
- copy[1] = (struct iovec) {
- .iov_base = (char[]) { '.', '.', '.' },
- .iov_len = 3,
- };
+ copy[1] = IOVEC_MAKE(((char[]){'.', '.', '.'}), 3);
mh.msg_iov = copy;
mh.msg_iovlen = 2;
return 0;
}
-static char* set_iovec_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) {
- char *x;
-
- x = strappend(field, value);
- if (x)
- iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
- return x;
-}
-
static char* set_iovec_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) {
char *x;
- x = set_iovec_field(iovec, n_iovec, field, value);
+ x = set_iovec_string_field(iovec, n_iovec, field, value);
free(value);
return x;
}
disable_coredumps();
}
- set_iovec_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]);
+ set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]);
}
if (cg_pid_get_user_unit(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t);
/* The next few are mandatory */
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME]))
return log_oom();
- if (!set_iovec_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM]))
+ if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM]))
return log_oom();
if (context[CONTEXT_EXE] &&
- !set_iovec_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE]))
+ !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE]))
return log_oom();
if (sd_pid_get_session(pid, &t) >= 0)
if (sd_pid_get_slice(pid, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_SLICE=", t);
- if (get_process_cmdline(pid, 0, false, &t) >= 0)
+ if (get_process_cmdline(pid, SIZE_MAX, 0, &t) >= 0)
set_iovec_field_free(iovec, n_iovec, "COREDUMP_CMDLINE=", t);
if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0)
iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t);
if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo))
- set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo));
+ set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo));
return 0; /* we successfully acquired all metadata */
}
log_debug("Processing coredump received from the kernel...");
- if (argc < CONTEXT_COMM + 1) {
- log_error("Not enough arguments passed by the kernel (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1);
- return -EINVAL;
- }
+ if (argc < CONTEXT_COMM + 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Not enough arguments passed by the kernel (%i, expected %i).",
+ argc - 1, CONTEXT_COMM + 1 - 1);
context[CONTEXT_PID] = argv[1 + CONTEXT_PID];
context[CONTEXT_UID] = argv[1 + CONTEXT_UID];
log_debug("Processing backtrace on stdin...");
- if (argc < CONTEXT_COMM + 1) {
- log_error("Not enough arguments passed (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1);
- return -EINVAL;
- }
+ if (argc < CONTEXT_COMM + 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Not enough arguments passed (%i, expected %i).",
+ argc - 1, CONTEXT_COMM + 1 - 1);
context[CONTEXT_PID] = argv[2 + CONTEXT_PID];
context[CONTEXT_UID] = argv[2 + CONTEXT_UID];
return r;
}
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
int r;
/* First, log to a safe place, since we don't know what crashed and it might
log_debug("Selected compression %s.", yes_no(arg_compress));
r = sd_listen_fds(false);
- if (r < 0) {
- log_error_errno(r, "Failed to determine number of file descriptor: %m");
- goto finish;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine the number of file descriptors: %m");
/* If we got an fd passed, we are running in coredumpd mode. Otherwise we
* are invoked from the kernel as coredump handler. */
if (r == 0) {
if (streq_ptr(argv[1], "--backtrace"))
- r = process_backtrace(argc, argv);
+ return process_backtrace(argc, argv);
else
- r = process_kernel(argc, argv);
+ return process_kernel(argc, argv);
} else if (r == 1)
- r = process_socket(SD_LISTEN_FDS_START);
- else {
- log_error("Received unexpected number of file descriptors.");
- r = -EINVAL;
- }
+ return process_socket(SD_LISTEN_FDS_START);
-finish:
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Received unexpected number of file descriptors.");
}
+
+DEFINE_MAIN_FUNCTION(run);