From 6e866b331d7cd4a5e0759dd160dea6edabd3678e Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Fri, 21 Dec 2018 22:06:22 +0100 Subject: New upstream version 240 --- src/coredump/coredump.c | 95 ++++++++++++++++++++++-------------------- src/coredump/coredumpctl.c | 100 ++++++++++++++++++++++++++------------------- src/coredump/meson.build | 6 ++- 3 files changed, 112 insertions(+), 89 deletions(-) (limited to 'src/coredump') diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 20a1cbdd45..0c888b26f9 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -34,6 +34,7 @@ #include "journal-importer.h" #include "log.h" #include "macro.h" +#include "main-func.h" #include "missing.h" #include "mkdir.h" #include "parse-util.h" @@ -45,6 +46,7 @@ #include "string-table.h" #include "string-util.h" #include "strv.h" +#include "tmpfile-util.h" #include "user-util.h" #include "util.h" @@ -55,10 +57,15 @@ #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 { @@ -340,21 +347,20 @@ static int save_external_coredump( 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); @@ -478,10 +484,9 @@ static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_s 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; @@ -511,7 +516,7 @@ static int compose_open_fds(pid_t pid, char **open_fds) { const char *fddelim = "", *path; struct dirent *dent = NULL; size_t size = 0; - int r = 0; + int r; assert(pid >= 0); assert(open_fds != NULL); @@ -534,7 +539,6 @@ static int compose_open_fds(pid_t pid, char **open_fds) { FOREACH_DIRENT(dent, proc_fd_dir, return -errno) { _cleanup_fclose_ FILE *fdinfo = NULL; _cleanup_free_ char *fdname = NULL; - char line[LINE_MAX]; int fd; r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname); @@ -549,16 +553,23 @@ static int compose_open_fds(pid_t pid, char **open_fds) { if (fd < 0) continue; - fdinfo = fdopen(fd, "re"); + fdinfo = fdopen(fd, "r"); if (!fdinfo) { safe_close(fd); continue; } - FOREACH_LINE(line, fdinfo, break) { + for (;;) { + _cleanup_free_ char *line = NULL; + + r = read_line(fdinfo, LONG_LINE_MAX, &line); + if (r < 0) + return r; + if (r == 0) + break; + fputs(line, stream); - if (!endswith(line, "\n")) - fputc('\n', stream); + fputc('\n', stream); } } @@ -672,7 +683,7 @@ static int change_uid_gid(const char *context[]) { if (uid <= SYSTEM_UID_MAX) { const char *user = "systemd-coredump"; - r = get_user_creds(&user, &uid, &gid, NULL, NULL); + r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0); if (r < 0) { log_warning_errno(r, "Cannot resolve %s user. Proceeding to dump core as root: %m", user); uid = gid = 0; @@ -871,9 +882,7 @@ static int process_socket(int fd) { assert(fd >= 0); - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); + log_setup_service(); log_debug("Processing coredump received on stdin..."); @@ -1226,10 +1235,10 @@ static int process_kernel(int argc, char* argv[]) { 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]; @@ -1283,10 +1292,10 @@ static int process_backtrace(int argc, char *argv[]) { 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]; @@ -1365,7 +1374,7 @@ static int process_backtrace(int argc, char *argv[]) { 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 @@ -1384,25 +1393,21 @@ int main(int argc, char *argv[]) { 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); diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index 99d07c14fb..fbee242962 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -15,22 +15,26 @@ #include "bus-error.h" #include "bus-util.h" #include "compress.h" +#include "def.h" #include "fd-util.h" -#include "fileio.h" #include "fs-util.h" #include "journal-internal.h" #include "journal-util.h" #include "log.h" #include "macro.h" +#include "main-func.h" #include "pager.h" #include "parse-util.h" #include "path-util.h" +#include "pretty-print.h" #include "process-util.h" +#include "rlimit-util.h" #include "sigbus.h" #include "signal-util.h" #include "string-util.h" #include "strv.h" #include "terminal-util.h" +#include "tmpfile-util.h" #include "user-util.h" #include "util.h" #include "verbs.h" @@ -41,10 +45,10 @@ static usec_t arg_since = USEC_INFINITY, arg_until = USEC_INFINITY; static const char* arg_field = NULL; static const char *arg_debugger = NULL; static const char *arg_directory = NULL; -static bool arg_no_pager = false; +static PagerFlags arg_pager_flags = 0; static int arg_no_legend = false; static int arg_one = false; -static FILE* arg_output = NULL; +static const char* arg_output = NULL; static bool arg_reverse = false; static bool arg_quiet = false; @@ -135,6 +139,13 @@ static int acquire_journal(sd_journal **ret, char **matches) { } static int help(void) { + _cleanup_free_ char *link = NULL; + int r; + + r = terminal_urlify_man("coredumpctl", "1", &link); + if (r < 0) + return log_oom(); + printf("%s [OPTIONS...]\n\n" "List or retrieve coredumps from the journal.\n\n" "Flags:\n" @@ -156,7 +167,10 @@ static int help(void) { " info [MATCHES...] Show detailed information about one or more coredumps\n" " dump [MATCHES...] Print first matching coredump to stdout\n" " debug [MATCHES...] Start a debugger for the first matching coredump\n" - , program_invocation_short_name); + "\nSee the %s for details.\n" + , program_invocation_short_name + , link + ); return 0; } @@ -199,7 +213,7 @@ static int parse_argv(int argc, char *argv[]) { return version(); case ARG_NO_PAGER: - arg_no_pager = true; + arg_pager_flags |= PAGER_DISABLE; break; case ARG_NO_LEGEND: @@ -211,34 +225,29 @@ static int parse_argv(int argc, char *argv[]) { break; case 'o': - if (arg_output) { - log_error("Cannot set output more than once."); - return -EINVAL; - } - - arg_output = fopen(optarg, "we"); - if (!arg_output) - return log_error_errno(errno, "writing to '%s': %m", optarg); + if (arg_output) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Cannot set output more than once."); + arg_output = optarg; break; case 'S': r = parse_timestamp(optarg, &arg_since); if (r < 0) - return log_error_errno(r, "Failed to parse timestamp: %s", optarg); + return log_error_errno(r, "Failed to parse timestamp '%s': %m", optarg); break; case 'U': r = parse_timestamp(optarg, &arg_until); if (r < 0) - return log_error_errno(r, "Failed to parse timestamp: %s", optarg); + return log_error_errno(r, "Failed to parse timestamp '%s': %m", optarg); break; case 'F': - if (arg_field) { - log_error("Cannot use --field/-F more than once."); - return -EINVAL; - } + if (arg_field) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Cannot use --field/-F more than once."); arg_field = optarg; break; @@ -266,10 +275,9 @@ static int parse_argv(int argc, char *argv[]) { } if (arg_since != USEC_INFINITY && arg_until != USEC_INFINITY && - arg_since > arg_until) { - log_error("--since= must be before --until=."); - return -EINVAL; - } + arg_since > arg_until) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "--since= must be before --until=."); return 1; } @@ -617,10 +625,9 @@ static int focus(sd_journal *j) { r = sd_journal_previous(j); if (r < 0) return log_error_errno(r, "Failed to search journal: %m"); - if (r == 0) { - log_error("No match found."); - return -ESRCH; - } + if (r == 0) + return log_error_errno(SYNTHETIC_ERRNO(ESRCH), + "No match found."); return r; } @@ -647,14 +654,15 @@ static int dump_list(int argc, char **argv, void *userdata) { if (r < 0) return r; - (void) pager_open(arg_no_pager, false); + (void) pager_open(arg_pager_flags); /* The coredumps are likely to compressed, and for just * listing them we don't need to decompress them, so let's * pick a fairly low data threshold here */ sd_journal_set_data_threshold(j, 4096); - if (arg_one) { + /* "info" without pattern implies "-1" */ + if (arg_one || (verb_is_info && argc == 1)) { r = focus(j); if (r < 0) return r; @@ -788,7 +796,8 @@ static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp) */ if (!file) { if (on_tty()) - return log_error_errno(ENOTTY, "Refusing to dump core to tty" + return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), + "Refusing to dump core to tty" " (use shell redirection or specify --output)."); file = stdout; } @@ -858,6 +867,7 @@ error: static int dump_core(int argc, char **argv, void *userdata) { _cleanup_(sd_journal_closep) sd_journal *j = NULL; + _cleanup_fclose_ FILE *f = NULL; int r; if (arg_field) { @@ -873,9 +883,15 @@ static int dump_core(int argc, char **argv, void *userdata) { if (r < 0) return r; - print_info(arg_output ? stdout : stderr, j, false); + if (arg_output) { + f = fopen(arg_output, "we"); + if (!f) + return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", arg_output); + } - r = save_core(j, arg_output, NULL, NULL); + print_info(f ? stdout : stderr, j, false); + + r = save_core(j, f, NULL, NULL); if (r < 0) return r; @@ -952,7 +968,7 @@ static int run_debug(int argc, char **argv, void *userdata) { fork_name = strjoina("(", arg_debugger, ")"); - r = safe_fork(fork_name, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_LOG, &pid); + r = safe_fork(fork_name, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid); if (r < 0) goto finish; if (r == 0) { @@ -976,7 +992,7 @@ finish: } static int check_units_active(void) { - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -1049,16 +1065,19 @@ static int coredumpctl_main(int argc, char *argv[]) { return dispatch_verb(argc, argv, verbs, NULL); } -int main(int argc, char *argv[]) { +static int run(int argc, char *argv[]) { int r, units_active; setlocale(LC_ALL, ""); log_parse_environment(); log_open(); + /* The journal merging logic potentially needs a lot of fds. */ + (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); + r = parse_argv(argc, argv); if (r <= 0) - goto end; + return r; sigbus_install(); @@ -1071,10 +1090,7 @@ int main(int argc, char *argv[]) { ansi_highlight_red(), units_active, units_active == 1 ? "unit is running" : "units are running", ansi_normal()); -end: - pager_close(); - - safe_fclose(arg_output); - - return r >= 0 ? r : EXIT_FAILURE; + return r; } + +DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); diff --git a/src/coredump/meson.build b/src/coredump/meson.build index bfba7ef58c..7fa5942697 100644 --- a/src/coredump/meson.build +++ b/src/coredump/meson.build @@ -13,8 +13,10 @@ endif coredumpctl_sources = files('coredumpctl.c') -install_data('coredump.conf', - install_dir : pkgsysconfdir) +if conf.get('ENABLE_COREDUMP') == 1 + install_data('coredump.conf', + install_dir : pkgsysconfdir) +endif tests += [ [['src/coredump/test-coredump-vacuum.c', -- cgit v1.2.1