Subject: [PATCH 06/11] journald: set a limit on the number of fields (1k)

We allocate a iovec entry for each field, so with many short entries,
our memory usage and processing time can be large, even with a relatively
small message size. Let's refuse overly long entries.

CVE-2018-16865
https://bugzilla.redhat.com/show_bug.cgi?id=1653861

What from I can see, the problem is not from an alloca, despite what the CVE
description says, but from the attack multiplication that comes from creating
many very small iovecs: (void* + size_t) for each three bytes of input message.

Subject: [PATCH 11/11] journal-remote: set a limit on the number of fields in
 a message

Existing use of E2BIG is replaced with ENOBUFS (entry too long), and E2BIG is
reused for the new error condition (too many fields).

This matches the change done for systemd-journald, hence forming the second
part of the fix for CVE-2018-16865
(https://bugzilla.redhat.com/show_bug.cgi?id=1653861).

diff -rup systemd-233/src/basic/journal-importer.c systemd-233-new/src/basic/journal-importer.c
--- systemd-233/src/basic/journal-importer.c	2017-03-01 13:43:06.000000000 -0800
+++ systemd-233-new/src/basic/journal-importer.c	2019-01-24 12:22:30.725192137 -0800
@@ -34,6 +34,9 @@ enum {
 };
 
 static int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) {
+        if (iovw->count >= ENTRY_FIELD_COUNT_MAX)
+                return -E2BIG;
+
         if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
                 return log_oom();
 
@@ -108,7 +111,7 @@ static int get_line(JournalImporter *imp
                 imp->scanned = imp->filled;
                 if (imp->scanned >= DATA_SIZE_MAX) {
                         log_error("Entry is bigger than %u bytes.", DATA_SIZE_MAX);
-                        return -E2BIG;
+                        return -ENOBUFS;
                 }
 
                 if (imp->passive_fd)
diff -rup systemd-233/src/basic/journal-importer.h systemd-233-new/src/basic/journal-importer.h
--- systemd-233/src/basic/journal-importer.h	2017-03-01 13:43:06.000000000 -0800
+++ systemd-233-new/src/basic/journal-importer.h	2019-01-24 12:17:34.949997181 -0800
@@ -31,6 +31,9 @@
 #define DATA_SIZE_MAX (1024*1024*768u)
 #define LINE_CHUNK 8*1024u
 
+/* The maximum number of fields in an entry */
+#define ENTRY_FIELD_COUNT_MAX 1024
+
 struct iovec_wrapper {
         struct iovec *iovec;
         size_t size_bytes;
diff -rup systemd-233/src/journal/journald-native.c systemd-233-new/src/journal/journald-native.c
--- systemd-233/src/journal/journald-native.c	2017-03-01 13:43:06.000000000 -0800
+++ systemd-233-new/src/journal/journald-native.c	2019-01-24 12:17:34.949997181 -0800
@@ -139,6 +139,10 @@ void server_process_native_message(
                 }
 
                 /* A property follows */
+                if (n > ENTRY_FIELD_COUNT_MAX) {
+                        log_debug("Received an entry that has more than " STRINGIFY(ENTRY_FIELD_COUNT_MAX) " fields, ignoring entry.");
+                        goto finish;
+                }
 
                 /* n existing properties, 1 new, +1 for _TRANSPORT */
                 if (!GREEDY_REALLOC(iovec, m, n + 2 + N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS)) {
diff -rup systemd-233/src/journal-remote/journal-remote.c systemd-233-new/src/journal-remote/journal-remote.c
--- systemd-233/src/journal-remote/journal-remote.c	2017-03-01 13:43:06.000000000 -0800
+++ systemd-233-new/src/journal-remote/journal-remote.c	2019-01-24 12:38:25.607372613 -0800
@@ -527,10 +527,14 @@ static int process_http_upload(
                         break;
                 else if (r < 0) {
                         log_warning("Failed to process data for connection %p", connection);
-                        if (r == -E2BIG)
+                        if (r == -ENOBUFS)
                                 return mhd_respondf(connection,
                                                     r, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
                                                     "Entry is too large, maximum is " STRINGIFY(DATA_SIZE_MAX) " bytes.");
+                        else if (r == -E2BIG)
+                                return mhd_respondf(connection,
+                                                    r, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
+                                                    "Entry with more fields than the maximum of " STRINGIFY(ENTRY_FIELD_COUNT_MAX) ".");
                         else
                                 return mhd_respondf(connection,
                                                     r, MHD_HTTP_UNPROCESSABLE_ENTITY,
@@ -1053,6 +1057,9 @@ static int handle_raw_source(sd_event_so
                 log_debug("%zu active sources remaining", s->active);
                 return 0;
         } else if (r == -E2BIG) {
+                log_notice("Entry with too many fields, skipped");
+                return 1;
+        } else if (r == -ENOBUFS) {
                 log_notice_errno(E2BIG, "Entry too big, skipped");
                 return 1;
         } else if (r == -EAGAIN) {