:: commit 65b261c28abdbc23554ec1bf07bde42c4db5d67b

Mintsuki <mintsuki@protonmail.com> — 2026-01-04 17:03

parents: 22a8a6d95c

multiboot1,multiboot2: Add bounds check to header search

diff --git a/common/protos/multiboot1.c b/common/protos/multiboot1.c
index 9114f7bd..791fc0cb 100644
--- a/common/protos/multiboot1.c
+++ b/common/protos/multiboot1.c
@@ -73,8 +73,18 @@ noreturn void multiboot1_load(char *config, char *cmdline) {
     struct multiboot1_header header = {0};
     size_t header_offset = 0;
 
-    for (header_offset = 0; header_offset < 8192; header_offset += 4) {
-        uint32_t v = *(uint32_t *)(kernel+header_offset);
+    // Per Multiboot spec, header must be within first 8192 bytes and 4-byte aligned.
+    // Ensure we don't read past end of file when checking magic or copying header.
+    size_t search_limit = 8192;
+    if (kernel_file_size < sizeof(struct multiboot1_header)) {
+        panic(true, "multiboot1: Kernel file too small to contain header");
+    }
+    if (search_limit > kernel_file_size - sizeof(struct multiboot1_header)) {
+        search_limit = kernel_file_size - sizeof(struct multiboot1_header);
+    }
+
+    for (header_offset = 0; header_offset <= search_limit; header_offset += 4) {
+        uint32_t v = *(uint32_t *)(kernel + header_offset);
 
         if (v == MULTIBOOT1_HEADER_MAGIC) {
             memcpy(&header, kernel + header_offset, sizeof(header));
diff --git a/common/protos/multiboot2.c b/common/protos/multiboot2.c
index e4acbf7e..59331257 100644
--- a/common/protos/multiboot2.c
+++ b/common/protos/multiboot2.c
@@ -90,9 +90,19 @@ noreturn void multiboot2_load(char *config, char* cmdline) {
 
     fclose(kernel_file);
 
-    struct multiboot_header *header;
+    struct multiboot_header *header = NULL;
 
-    for (size_t header_offset = 0; header_offset < MULTIBOOT_SEARCH; header_offset += MULTIBOOT_HEADER_ALIGN) {
+    // Per Multiboot2 spec, header must be within first 32768 bytes and 8-byte aligned.
+    // Ensure we don't read past end of file when checking magic.
+    size_t search_limit = MULTIBOOT_SEARCH;
+    if (kernel_file_size < sizeof(struct multiboot_header)) {
+        panic(true, "multiboot2: Kernel file too small to contain header");
+    }
+    if (search_limit > kernel_file_size - sizeof(struct multiboot_header)) {
+        search_limit = kernel_file_size - sizeof(struct multiboot_header);
+    }
+
+    for (size_t header_offset = 0; header_offset <= search_limit; header_offset += MULTIBOOT_HEADER_ALIGN) {
         header = (void *)(kernel + header_offset);
 
         if (header->magic == MULTIBOOT2_HEADER_MAGIC) {
@@ -100,7 +110,7 @@ noreturn void multiboot2_load(char *config, char* cmdline) {
         }
     }
 
-    if (header->magic != MULTIBOOT2_HEADER_MAGIC) {
+    if (header == NULL || header->magic != MULTIBOOT2_HEADER_MAGIC) {
         panic(true, "multiboot2: Invalid magic");
     }
 
tab: 248 wrap: offon