Blame SOURCES/0081-journald-when-processing-a-native-message-bail-more-.patch

a3e2b5
From ed028441cc2ef0ffb9771d7266d40f18910f0ae1 Mon Sep 17 00:00:00 2001
a3e2b5
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
a3e2b5
Date: Wed, 5 Dec 2018 22:50:39 +0100
a3e2b5
Subject: [PATCH] journald: when processing a native message, bail more quickly
a3e2b5
 on overbig messages
a3e2b5
a3e2b5
We'd first parse all or most of the message, and only then consider if it
a3e2b5
is not too large. Also, when encountering a single field over the limit,
a3e2b5
we'd still process the preceding part of the message. Let's be stricter,
a3e2b5
and check size limits early, and let's refuse the whole message if it fails
a3e2b5
any of the size limits.
a3e2b5
a3e2b5
(cherry-picked from commit 964ef920ea6735d39f856b05fd8ef451a09a6a1d)
a3e2b5
a3e2b5
Related: #1664977
a3e2b5
---
a3e2b5
 src/journal/journald-native.c | 65 ++++++++++++++++++++---------------
a3e2b5
 1 file changed, 37 insertions(+), 28 deletions(-)
a3e2b5
a3e2b5
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
a3e2b5
index 951d092053..110ab3641c 100644
a3e2b5
--- a/src/journal/journald-native.c
a3e2b5
+++ b/src/journal/journald-native.c
a3e2b5
@@ -109,7 +109,7 @@ static int server_process_entry(
a3e2b5
         int priority = LOG_INFO;
a3e2b5
         pid_t object_pid = 0;
a3e2b5
         const char *p;
a3e2b5
-        int r = 0;
a3e2b5
+        int r = 1;
a3e2b5
 
a3e2b5
         p = buffer;
a3e2b5
 
a3e2b5
@@ -121,8 +121,7 @@ static int server_process_entry(
a3e2b5
                 if (!e) {
a3e2b5
                         /* Trailing noise, let's ignore it, and flush what we collected */
a3e2b5
                         log_debug("Received message with trailing noise, ignoring.");
a3e2b5
-                        r = 1; /* finish processing of the message */
a3e2b5
-                        break;
a3e2b5
+                        break; /* finish processing of the message */
a3e2b5
                 }
a3e2b5
 
a3e2b5
                 if (e == p) {
a3e2b5
@@ -132,8 +131,7 @@ static int server_process_entry(
a3e2b5
                 }
a3e2b5
 
a3e2b5
                 if (IN_SET(*p, '.', '#')) {
a3e2b5
-                        /* Ignore control commands for now, and
a3e2b5
-                         * comments too. */
a3e2b5
+                        /* Ignore control commands for now, and comments too. */
a3e2b5
                         *remaining -= (e - p) + 1;
a3e2b5
                         p = e + 1;
a3e2b5
                         continue;
a3e2b5
@@ -142,7 +140,6 @@ static int server_process_entry(
a3e2b5
                 /* A property follows */
a3e2b5
                 if (n > ENTRY_FIELD_COUNT_MAX) {
a3e2b5
                         log_debug("Received an entry that has more than " STRINGIFY(ENTRY_FIELD_COUNT_MAX) " fields, ignoring entry.");
a3e2b5
-                        r = 1;
a3e2b5
                         goto finish;
a3e2b5
                 }
a3e2b5
 
a3e2b5
@@ -152,7 +149,7 @@ static int server_process_entry(
a3e2b5
                                     N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS +
a3e2b5
                                     client_context_extra_fields_n_iovec(context))) {
a3e2b5
                         r = log_oom();
a3e2b5
-                        break;
a3e2b5
+                        goto finish;
a3e2b5
                 }
a3e2b5
 
a3e2b5
                 q = memchr(p, '=', e - p);
a3e2b5
@@ -161,6 +158,16 @@ static int server_process_entry(
a3e2b5
                                 size_t l;
a3e2b5
 
a3e2b5
                                 l = e - p;
a3e2b5
+                                if (l > DATA_SIZE_MAX) {
a3e2b5
+                                        log_debug("Received text block of %zu bytes is too large, ignoring entry.", l);
a3e2b5
+                                        goto finish;
a3e2b5
+                                }
a3e2b5
+
a3e2b5
+                                if (entry_size + l + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
a3e2b5
+                                        log_debug("Entry is too big (%zu bytes after processing %zu entries), ignoring entry.",
a3e2b5
+                                                  entry_size + l, n + 1);
a3e2b5
+                                        goto finish;
a3e2b5
+                                }
a3e2b5
 
a3e2b5
                                 /* If the field name starts with an underscore, skip the variable, since that indicates
a3e2b5
                                  * a trusted field */
a3e2b5
@@ -178,7 +185,7 @@ static int server_process_entry(
a3e2b5
                         p = e + 1;
a3e2b5
                         continue;
a3e2b5
                 } else {
a3e2b5
-                        uint64_t l;
a3e2b5
+                        uint64_t l, total;
a3e2b5
                         char *k;
a3e2b5
 
a3e2b5
                         if (*remaining < e - p + 1 + sizeof(uint64_t) + 1) {
a3e2b5
@@ -187,10 +194,16 @@ static int server_process_entry(
a3e2b5
                         }
a3e2b5
 
a3e2b5
                         l = unaligned_read_le64(e + 1);
a3e2b5
-
a3e2b5
                         if (l > DATA_SIZE_MAX) {
a3e2b5
-                                log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l);
a3e2b5
-                                break;
a3e2b5
+                                log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring entry.", l);
a3e2b5
+                                goto finish;
a3e2b5
+                        }
a3e2b5
+
a3e2b5
+                        total = (e - p) + 1 + l;
a3e2b5
+                        if (entry_size + total + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
a3e2b5
+                                log_debug("Entry is too big (%"PRIu64"bytes after processing %zu fields), ignoring.",
a3e2b5
+                                          entry_size + total, n + 1);
a3e2b5
+                                goto finish;
a3e2b5
                         }
a3e2b5
 
a3e2b5
                         if ((uint64_t) *remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
a3e2b5
@@ -199,7 +212,7 @@ static int server_process_entry(
a3e2b5
                                 break;
a3e2b5
                         }
a3e2b5
 
a3e2b5
-                        k = malloc((e - p) + 1 + l);
a3e2b5
+                        k = malloc(total);
a3e2b5
                         if (!k) {
a3e2b5
                                 log_oom();
a3e2b5
                                 break;
a3e2b5
@@ -228,15 +241,8 @@ static int server_process_entry(
a3e2b5
                 }
a3e2b5
         }
a3e2b5
 
a3e2b5
-        if (n <= 0) {
a3e2b5
-                r = 1;
a3e2b5
+        if (n <= 0)
a3e2b5
                 goto finish;
a3e2b5
-        }
a3e2b5
-
a3e2b5
-        if (!client_context_test_priority(context, priority)) {
a3e2b5
-                r = 0;
a3e2b5
-                goto finish;
a3e2b5
-        }
a3e2b5
 
a3e2b5
         tn = n++;
a3e2b5
         iovec[tn] = IOVEC_MAKE_STRING("_TRANSPORT=journal");
a3e2b5
@@ -247,6 +253,11 @@ static int server_process_entry(
a3e2b5
                 goto finish;
a3e2b5
         }
a3e2b5
 
a3e2b5
+        r = 0; /* Success, we read the message. */
a3e2b5
+
a3e2b5
+        if (!client_context_test_priority(context, priority))
a3e2b5
+                goto finish;
a3e2b5
+
a3e2b5
         if (message) {
a3e2b5
                 if (s->forward_to_syslog)
a3e2b5
                         server_forward_syslog(s, syslog_fixup_facility(priority), identifier, message, ucred, tv);
a3e2b5
@@ -318,15 +329,13 @@ void server_process_native_file(
a3e2b5
         bool sealed;
a3e2b5
         int r;
a3e2b5
 
a3e2b5
-        /* Data is in the passed fd, since it didn't fit in a
a3e2b5
-         * datagram. */
a3e2b5
+        /* Data is in the passed fd, probably it didn't fit in a datagram. */
a3e2b5
 
a3e2b5
         assert(s);
a3e2b5
         assert(fd >= 0);
a3e2b5
 
a3e2b5
         /* If it's a memfd, check if it is sealed. If so, we can just
a3e2b5
-         * use map it and use it, and do not need to copy the data
a3e2b5
-         * out. */
a3e2b5
+         * mmap it and use it, and do not need to copy the data out. */
a3e2b5
         sealed = memfd_get_sealed(fd) > 0;
a3e2b5
 
a3e2b5
         if (!sealed && (!ucred || ucred->uid != 0)) {
a3e2b5
@@ -397,7 +406,7 @@ void server_process_native_file(
a3e2b5
                 ssize_t n;
a3e2b5
 
a3e2b5
                 if (fstatvfs(fd, &vfs) < 0) {
a3e2b5
-                        log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m");
a3e2b5
+                        log_error_errno(errno, "Failed to stat file system of passed file, not processing it: %m");
a3e2b5
                         return;
a3e2b5
                 }
a3e2b5
 
a3e2b5
@@ -407,7 +416,7 @@ void server_process_native_file(
a3e2b5
                  * https://github.com/systemd/systemd/issues/1822
a3e2b5
                  */
a3e2b5
                 if (vfs.f_flag & ST_MANDLOCK) {
a3e2b5
-                        log_error("Received file descriptor from file system with mandatory locking enabled, refusing.");
a3e2b5
+                        log_error("Received file descriptor from file system with mandatory locking enabled, not processing it.");
a3e2b5
                         return;
a3e2b5
                 }
a3e2b5
 
a3e2b5
@@ -420,13 +429,13 @@ void server_process_native_file(
a3e2b5
                  * and so is SMB. */
a3e2b5
                 r = fd_nonblock(fd, true);
a3e2b5
                 if (r < 0) {
a3e2b5
-                        log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m");
a3e2b5
+                        log_error_errno(r, "Failed to make fd non-blocking, not processing it: %m");
a3e2b5
                         return;
a3e2b5
                 }
a3e2b5
 
a3e2b5
                 /* The file is not sealed, we can't map the file here, since
a3e2b5
                  * clients might then truncate it and trigger a SIGBUS for
a3e2b5
-                 * us. So let's stupidly read it */
a3e2b5
+                 * us. So let's stupidly read it. */
a3e2b5
 
a3e2b5
                 p = malloc(st.st_size);
a3e2b5
                 if (!p) {