chiark / gitweb /
journal: fix off-by-one error in native message iovec counting
[elogind.git] / src / journal / journald-native.c
index 4e44c3ada78c4d16c05ba38f12ff6a54c749b603..f878dfc911a719a0501f961264a2e9b228f5d905 100644 (file)
 #include <sys/epoll.h>
 
 #include "socket-util.h"
-#include "journald.h"
+#include "path-util.h"
+#include "journald-server.h"
 #include "journald-native.h"
 #include "journald-kmsg.h"
 #include "journald-console.h"
 #include "journald-syslog.h"
 
-#define ENTRY_SIZE_MAX (1024*1024*32)
+/* Make sure not to make this smaller than the maximum coredump
+ * size. See COREDUMP_MAX in coredump.c */
+#define ENTRY_SIZE_MAX (1024*1024*768)
+#define DATA_SIZE_MAX (1024*1024*768)
 
 static bool valid_user_field(const char *p, size_t l) {
         const char *a;
@@ -119,11 +123,12 @@ void server_process_native_message(
 
                 /* A property follows */
 
-                if (n+N_IOVEC_META_FIELDS >= m) {
+                /* n received properties, +1 for _TRANSPORT */
+                if (n + 1 + N_IOVEC_META_FIELDS >= m) {
                         struct iovec *c;
                         unsigned u;
 
-                        u = MAX((n+N_IOVEC_META_FIELDS+1) * 2U, 4U);
+                        u = MAX((n + 1 + N_IOVEC_META_FIELDS) * 2U, 4U);
                         c = realloc(iovec, u * sizeof(struct iovec));
                         if (!c) {
                                 log_oom();
@@ -205,7 +210,12 @@ void server_process_native_message(
                         memcpy(&l_le, e + 1, sizeof(uint64_t));
                         l = le64toh(l_le);
 
-                        if (remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
+                        if (l > DATA_SIZE_MAX) {
+                                log_debug("Received binary data block too large, ignoring.");
+                                break;
+                        }
+
+                        if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
                             e[1+sizeof(uint64_t)+l] != '\n') {
                                 log_debug("Failed to parse message, ignoring.");
                                 break;
@@ -275,12 +285,44 @@ void server_process_native_file(
                 const char *label, size_t label_len) {
 
         struct stat st;
-        void *p;
+        _cleanup_free_ void *p = NULL;
         ssize_t n;
+        int r;
 
         assert(s);
         assert(fd >= 0);
 
+        if (!ucred || ucred->uid != 0) {
+                _cleanup_free_ char *sl = NULL, *k = NULL;
+                const char *e;
+
+                if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
+                        log_oom();
+                        return;
+                }
+
+                r = readlink_malloc(sl, &k);
+                if (r < 0) {
+                        log_error("readlink(%s) failed: %m", sl);
+                        return;
+                }
+
+                e = path_startswith(k, "/dev/shm/");
+                if (!e)
+                        e = path_startswith(k, "/tmp/");
+                if (!e)
+                        e = path_startswith(k, "/var/tmp/");
+                if (!e) {
+                        log_error("Received file outside of allowed directories. Refusing.");
+                        return;
+                }
+
+                if (!filename_is_safe(e)) {
+                        log_error("Received file in subdirectory of allowed directories. Refusing.");
+                        return;
+                }
+        }
+
         /* Data is in the passed file, since it didn't fit in a
          * datagram. We can't map the file here, since clients might
          * then truncate it and trigger a SIGBUS for us. So let's
@@ -315,8 +357,6 @@ void server_process_native_file(
                 log_error("Failed to read file, ignoring: %s", strerror(-n));
         else if (n > 0)
                 server_process_native_message(s, p, n, ucred, tv, label, label_len);
-
-        free(p);
 }
 
 int server_open_native_socket(Server*s) {
@@ -359,7 +399,7 @@ int server_open_native_socket(Server*s) {
 
 #ifdef HAVE_SELINUX
         one = 1;
-        r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
+        r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
         if (r < 0)
                 log_warning("SO_PASSSEC failed: %m");
 #endif