]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: check size before mmap
authorTobias Stoeckmann <tobias@stoeckmann.org>
Wed, 2 Mar 2022 21:03:26 +0000 (22:03 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 3 Mar 2022 21:48:43 +0000 (22:48 +0100)
The data type off_t can be 64 on 32 bit systems if they have large
file support. Since mmap expects a size_t with 32 bits as second
argument truncation could occur. At worst these huge files could
lead to mmaps smaller than the previous check for small files.

This in turn shouldn't have a lot of impact because mmap allocates
at page size boundaries. This also made the PAGE_ALIGN call in
open_mmap unneeded. In fact it was neither in sync with other mmap
calls nor with its own munmap counterpart in error path.

If such large files are encountered, which is very unlikely in these
code paths, treat them with the same error as if they are too small.

src/basic/fileio.h
src/basic/locale-util.c
src/boot/bootctl.c
src/libsystemd/sd-hwdb/sd-hwdb.c
src/libsystemd/sd-journal/catalog.c
src/libsystemd/sd-journal/compress.c

index cea3dd893d1f3d10f81f1436027618c4c5000436..9151d8237a84baea806c92a5a8e9132912a628d2 100644 (file)
@@ -110,6 +110,12 @@ typedef enum ReadLineFlags {
 
 int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret);
 
+static inline bool file_offset_beyond_memory_size(off_t x) {
+        if (x < 0) /* off_t is signed, filter that out */
+                return false;
+        return (uint64_t) x > (uint64_t) SIZE_MAX;
+}
+
 static inline int read_line(FILE *f, size_t limit, char **ret) {
         return read_line_full(f, limit, 0, ret);
 }
index 7f1a2f15f71caed6b8d1139112c90e038cf0e348..cb99641263b0a53f06bc6bca887b29f11eb0c138 100644 (file)
@@ -14,6 +14,7 @@
 #include "dirent-util.h"
 #include "env-util.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "hashmap.h"
 #include "locale-util.h"
 #include "path-util.h"
@@ -112,6 +113,9 @@ static int add_locales_from_archive(Set *locales) {
         if (st.st_size < (off_t) sizeof(struct locarhead))
                 return -EBADMSG;
 
+        if (file_offset_beyond_memory_size(st.st_size))
+                return -EFBIG;
+
         p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
         if (p == MAP_FAILED)
                 return -errno;
index c81411c85797e62179c62fa7be66e67ad313638e..1f4dd69d08969cad68ac205e5de6354b4be14bb5 100644 (file)
@@ -219,7 +219,7 @@ static int get_file_version(int fd, char **v) {
         if (r < 0)
                 return log_error_errno(r, "EFI binary is not a regular file: %m");
 
-        if (st.st_size < 27) {
+        if (st.st_size < 27 || file_offset_beyond_memory_size(st.st_size)) {
                 *v = NULL;
                 return 0;
         }
index 53601765fe7f4799c0059532d19f498673cdf27d..748cf26934969ec92c9d130619e1eee4f53d907f 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "alloc-util.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "hashmap.h"
 #include "hwdb-internal.h"
 #include "nulstr-util.h"
@@ -312,6 +313,9 @@ _public_ int sd_hwdb_new(sd_hwdb **ret) {
         if (hwdb->st.st_size < (off_t) offsetof(struct trie_header_f, strings_len) + 8)
                 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
                                        "File %s is too short: %m", hwdb_bin_path);
+        if (file_offset_beyond_memory_size(hwdb->st.st_size))
+                return log_debug_errno(SYNTHETIC_ERRNO(EFBIG),
+                                       "File %s is too long: %m", hwdb_bin_path);
 
         hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0);
         if (hwdb->map == MAP_FAILED)
index 16bd4a63f1d9389773c6d49d49f019d09d7ef06c..e2397f47e3a41e3bc974891122363d35b45fde3c 100644 (file)
@@ -521,10 +521,10 @@ static int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p
         if (fstat(fd, &st) < 0)
                 return -errno;
 
-        if (st.st_size < (off_t) sizeof(CatalogHeader))
+        if (st.st_size < (off_t) sizeof(CatalogHeader) || file_offset_beyond_memory_size(st.st_size))
                 return -EINVAL;
 
-        p = mmap(NULL, PAGE_ALIGN(st.st_size), PROT_READ, MAP_SHARED, fd, 0);
+        p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
         if (p == MAP_FAILED)
                 return -errno;
 
index 837abab76c8139860fbd747b03397c775f962fc4..cb2e82667f75cca2362d0e2af5d34977fb75393d 100644 (file)
@@ -25,6 +25,7 @@
 #include "alloc-util.h"
 #include "compress.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "io-util.h"
 #include "journal-def.h"
 #include "macro.h"
@@ -807,6 +808,9 @@ int decompress_stream_lz4(int in, int out, uint64_t max_bytes) {
         if (fstat(in, &st) < 0)
                 return log_debug_errno(errno, "fstat() failed: %m");
 
+        if (file_offset_beyond_memory_size(st.st_size))
+                return -EFBIG;
+
         buf = malloc(LZ4_BUFSIZE);
         if (!buf)
                 return -ENOMEM;