:: commit 94c7ffaa3906cf70bf6361e94e2668b7dd0c348b

Mintsuki <mintsuki@protonmail.com> — 2026-01-12 21:25

parents: 6875b2ad84

pe: Add bounds check for e_lfanew offset in pe_bits

diff --git a/common/lib/pe.c b/common/lib/pe.c
index 8a757f08..6ed3d6ca 100644
--- a/common/lib/pe.c
+++ b/common/lib/pe.c
@@ -196,13 +196,21 @@ static void pe64_validate(uint8_t *image, size_t file_size) {
 #endif
 }
 
-int pe_bits(uint8_t *image) {
+int pe_bits(uint8_t *image, size_t image_size) {
+    if (image_size < sizeof(IMAGE_DOS_HEADER)) {
+        return -1;
+    }
+
     IMAGE_DOS_HEADER *dos_hdr = (IMAGE_DOS_HEADER *)image;
 
     if (dos_hdr->e_magic != IMAGE_DOS_SIGNATURE) {
         return -1;
     }
 
+    if ((size_t)dos_hdr->e_lfanew > image_size - sizeof(IMAGE_NT_HEADERS64)) {
+        return -1;
+    }
+
     IMAGE_NT_HEADERS64 *nt_hdrs = (IMAGE_NT_HEADERS64 *)(image + dos_hdr->e_lfanew);
 
     if (nt_hdrs->Signature != IMAGE_NT_SIGNATURE) {
diff --git a/common/lib/pe.h b/common/lib/pe.h
index 0725efb0..7923916c 100644
--- a/common/lib/pe.h
+++ b/common/lib/pe.h
@@ -5,7 +5,7 @@
 #include <stdbool.h>
 #include <lib/misc.h>
 
-int pe_bits(uint8_t *image);
+int pe_bits(uint8_t *image, size_t image_size);
 
 bool pe64_load(uint8_t *image, size_t file_size, uint64_t *entry_point, uint64_t *_slide, uint32_t alloc_type, bool kaslr, struct mem_range **ranges, uint64_t *ranges_count, uint64_t *physical_base, uint64_t *virtual_base, uint64_t *image_size, uint64_t *image_size_before_bss, bool *is_reloc);
 
diff --git a/common/protos/limine.c b/common/protos/limine.c
index 0c257e27..f6f05c18 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -40,10 +40,10 @@ enum executable_format {
     EXECUTABLE_FORMAT_PE,
 };
 
-static enum executable_format detect_kernel_format(uint8_t *kernel) {
+static enum executable_format detect_kernel_format(uint8_t *kernel, size_t kernel_size) {
     if (elf_bits(kernel) != -1) {
         return EXECUTABLE_FORMAT_ELF;
-    } else if (pe_bits(kernel) != -1) {
+    } else if (pe_bits(kernel, kernel_size) != -1) {
         return EXECUTABLE_FORMAT_PE;
     } else {
         panic(true, "limine: Unknown kernel executable format");
@@ -471,7 +471,7 @@ noreturn void limine_load(char *config, char *cmdline) {
     uint64_t image_size_before_bss;
     bool is_reloc;
 
-    enum executable_format kernel_format = detect_kernel_format(kernel);
+    enum executable_format kernel_format = detect_kernel_format(kernel, kernel_file->size);
     switch (kernel_format) {
         case EXECUTABLE_FORMAT_ELF:
             if (!elf64_load(kernel, &entry_point, &slide,
tab: 248 wrap: offon