:: commit c16a59584667ad8e2c34c96fe2c6e447a9a7231d

Mintsuki <mintsuki@protonmail.com> — 2026-01-13 04:15

parents: 970709b2c7

linux: Add bounds checks for kernel file reads

diff --git a/common/protos/linux_x86.c b/common/protos/linux_x86.c
index f9fba8e5..961565ad 100644
--- a/common/protos/linux_x86.c
+++ b/common/protos/linux_x86.c
@@ -304,6 +304,11 @@ noreturn void linux_load(char *config, char *cmdline) {
     if ((kernel_file = uri_open(kernel_path)) == NULL)
         panic(true, "linux: Failed to open kernel with path `%#`. Is the path correct?", kernel_path);
 
+    // Minimum size check: need at least 0x206 bytes for signature at 0x202
+    if (kernel_file->size < 0x206) {
+        panic(true, "linux: Kernel file too small");
+    }
+
 #if defined (UEFI) && defined (__x86_64__)
     bool use_64_bit_proto = false;
 #endif
@@ -326,6 +331,10 @@ noreturn void linux_load(char *config, char *cmdline) {
 
     size_t real_mode_code_size = 512 + setup_code_size;
 
+    if (real_mode_code_size > kernel_file->size) {
+        panic(true, "linux: Kernel file too small for real mode code");
+    }
+
     struct boot_params *boot_params = ext_mem_alloc(sizeof(struct boot_params));
 
     struct setup_header *setup_header = &boot_params->hdr;
@@ -336,6 +345,10 @@ noreturn void linux_load(char *config, char *cmdline) {
         0x202 + x;
     });
 
+    if (setup_header_end > kernel_file->size) {
+        panic(true, "linux: Kernel file too small for setup header");
+    }
+
     fread(kernel_file, setup_header, 0x1f1, setup_header_end - 0x1f1);
 
     printv("linux: Boot protocol: %u.%u\n",
@@ -353,8 +366,12 @@ noreturn void linux_load(char *config, char *cmdline) {
     if (verbose) {
         char *kernel_version = ext_mem_alloc(128);
         if (setup_header->kernel_version != 0) {
-            fread(kernel_file, kernel_version, setup_header->kernel_version + 0x200, 128);
-            print("linux: Kernel version: %s\n", kernel_version);
+            size_t version_offset = (size_t)setup_header->kernel_version + 0x200;
+            if (version_offset + 128 <= kernel_file->size) {
+                fread(kernel_file, kernel_version, version_offset, 128);
+                kernel_version[127] = '\0';
+                print("linux: Kernel version: %s\n", kernel_version);
+            }
         }
         pmm_free(kernel_version, 128);
     }
tab: 248 wrap: offon