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,
