]> 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)
committerLuca Boccassi <luca.boccassi@gmail.com>
Fri, 27 Feb 2026 21:57:04 +0000 (21:57 +0000)
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

(cherry picked from commit e67b008fa35d92937b07c6b3903419cd42ef9103)
(cherry picked from commit d33dbbc6133632f8541af219907cb95bd14ad9ec)
(cherry picked from commit 13dd43b83b2e9322e02f757d362b35b0b4af729a)

docs/ENVIRONMENT.md
src/journal/journald-native.c
src/shared/journal-importer.h

index 459461eb5e92a00fbe8c0d5011fee7826132619e..5029a52fb99287440c547d020b3fbf6a1ee114ba 100644 (file)
@@ -619,6 +619,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 417f2c5b88a8dd74e81f0ede0ea891e2af92ed70..f330109d8726b0ee4210699419e3e884d4d6b9df 100644 (file)
@@ -327,6 +327,52 @@ void server_process_native_message(
         } while (r == 0);
 }
 
+static size_t entry_size_max_by_ucred(Server *s, const struct ucred *ucred, const char *label, size_t label_len) {
+        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(s, ucred->pid, ucred, label, label_len, /* 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 server_process_native_file(
                 Server *s,
                 int fd,
@@ -391,7 +437,7 @@ int server_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(s, ucred, label, label_len) / (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 d84dcc4bb0b38060fdcd8357e1a40173b3edf448..bb323e18561610c262b187e74bc185524d530af9 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