From e67b008fa35d92937b07c6b3903419cd42ef9103 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Thu, 5 Feb 2026 00:39:35 +0000 Subject: [PATCH] journald: set a lower size limit for FDs from unpriv processes Unprivileged processes can send 768M in a FD-based message to journald, which will be malloc'ed in one go, likely causing memory issues. Set the limit for unprivileged users to 24M. Allow coredumps as an exception, since we always allowed storing up to the 768M max core files in the journal. Reported on yeswehack.com as #YWH-PGM9780-48 --- docs/ENVIRONMENT.md | 4 +++ src/journal/journald-native.c | 48 ++++++++++++++++++++++++++++++++++- src/shared/journal-importer.h | 2 ++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 8df82d5ba2a..fb2984b0ecb 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -671,6 +671,10 @@ SYSTEMD_HOME_DEBUG_SUFFIX=foo \ specified algorithm takes an effect immediately, you need to explicitly run `journalctl --rotate`. +* `$SYSTEMD_JOURNAL_FD_SIZE_MAX` – Takes a size with the usual suffixes (K, M, ...) in + string format. Overrides the default maximum allowed size for a file-descriptor + based input record to be stored in the journal. + * `$SYSTEMD_CATALOG` – path to the compiled catalog database file to use for `journalctl -x`, `journalctl --update-catalog`, `journalctl --list-catalog` and related calls. diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 25b842a58ff..d61e8f5a743 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -328,6 +328,52 @@ void manager_process_native_message( } while (r == 0); } +static size_t entry_size_max_by_ucred(Manager *m, const struct ucred *ucred, const char *label) { + static uint64_t entry_size_max = UINT64_MAX; + static bool entry_size_max_checked = false; + int r; + + if (entry_size_max != UINT64_MAX) + return entry_size_max; + if (!entry_size_max_checked) { + const char *p; + + entry_size_max_checked = true; + + p = secure_getenv("SYSTEMD_JOURNAL_FD_SIZE_MAX"); + if (p) { + r = parse_size(p, 1024, &entry_size_max); + if (r < 0) + log_warning_errno(r, "Failed to parse $SYSTEMD_JOURNAL_FD_SIZE_MAX, ignoring: %m"); + else + return entry_size_max; + } + } + + /* Check for unprivileged senders, as the default limit of 768M is quite high and the socket is + * unprivileged, to avoid abuses. */ + + if (!ucred) + return ENTRY_SIZE_UNPRIV_MAX; + if (ucred->uid == 0) /* Shortcut for root senders */ + return ENTRY_SIZE_MAX; + + /* As an exception, allow coredumps to use the old max size for backward compatibility */ + if (pid_is_valid(ucred->pid)) { + ClientContext *context = NULL; + + r = client_context_get(m, ucred->pid, ucred, label, /* unit_id= */ NULL, &context); + if (r < 0) + log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, + "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m", + ucred->pid); + else if (context->unit && startswith(context->unit, "systemd-coredump@")) + return ENTRY_SIZE_MAX; + } + + return ENTRY_SIZE_UNPRIV_MAX; +} + int manager_process_native_file( Manager *m, int fd, @@ -392,7 +438,7 @@ int manager_process_native_file( /* When !sealed, set a lower memory limit. We have to read the file, effectively doubling memory * use. */ - if (st.st_size > ENTRY_SIZE_MAX / (sealed ? 1 : 2)) + if ((size_t) st.st_size > entry_size_max_by_ucred(m, ucred, label) / (sealed ? 1 : 2)) return log_ratelimit_error_errno(SYNTHETIC_ERRNO(EFBIG), JOURNAL_LOG_RATELIMIT, "File passed too large (%"PRIu64" bytes), refusing.", (uint64_t) st.st_size); diff --git a/src/shared/journal-importer.h b/src/shared/journal-importer.h index 1a9f5b366ac..f218d80dfd9 100644 --- a/src/shared/journal-importer.h +++ b/src/shared/journal-importer.h @@ -12,9 +12,11 @@ * See JOURNAL_SIZE_MAX in coredump.c */ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION #define ENTRY_SIZE_MAX (1024*1024*770u) +#define ENTRY_SIZE_UNPRIV_MAX (1024*1024*32u) #define DATA_SIZE_MAX (1024*1024*768u) #else #define ENTRY_SIZE_MAX (1024*1024*13u) +#define ENTRY_SIZE_UNPRIV_MAX (1024*1024*8u) #define DATA_SIZE_MAX (1024*1024*11u) #endif #define LINE_CHUNK 8*1024u -- 2.47.3