]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journald: set a lower size limit for FDs from unpriv processes
authorLuca Boccassi <luca.boccassi@gmail.com>
Thu, 5 Feb 2026 00:39:35 +0000 (00:39 +0000)
committerLennart Poettering <lennart@poettering.net>
Mon, 9 Feb 2026 12:51:59 +0000 (13:51 +0100)
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
src/journal/journald-native.c
src/shared/journal-importer.h

index 8df82d5ba2a707002fecbbd32711ed44a5335790..fb2984b0ecb78d4d52b71b9faab5465c6fed60bb 100644 (file)
@@ -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.
index 25b842a58ffc897981b8ebd86a408a34ed92138d..d61e8f5a743f7e622e58929aedcb1285eaf4bd09 100644 (file)
@@ -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);
index 1a9f5b366ace957e4c62218d6589c464871f3215..f218d80dfd938495bdfb122d13a443bd402fbf90 100644 (file)
  * 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