:: commit d80c72848c04531b7b2bf676c74d17be67ff2c34

Mintsuki <mintsuki@protonmail.com> — 2026-02-07 08:18

parents: 1f4c65c456

lib/elf: Validate section header offsets against file size in elf64_load_section

diff --git a/common/lib/elf.c b/common/lib/elf.c
index 58eb12a3..69530418 100644
--- a/common/lib/elf.c
+++ b/common/lib/elf.c
@@ -610,7 +610,7 @@ end_of_pt_segment:
     return true;
 }
 
-bool elf64_load_section(uint8_t *elf, void *buffer, const char *name, size_t limit, uint64_t slide) {
+bool elf64_load_section(uint8_t *elf, size_t file_size, void *buffer, const char *name, size_t limit, uint64_t slide) {
     struct elf64_hdr *hdr = (void *)elf;
 
     elf64_validate(hdr);
@@ -627,14 +627,35 @@ bool elf64_load_section(uint8_t *elf, void *buffer, const char *name, size_t lim
         return false;
     }
 
+    // Validate section header table is within file bounds
+    uint64_t shdr_table_end = (uint64_t)hdr->shoff + (uint64_t)hdr->sh_num * hdr->shdr_size;
+    if (shdr_table_end > file_size) {
+        return false;
+    }
+
     struct elf64_shdr *shstrtab = (void *)elf + (hdr->shoff + hdr->shstrndx * hdr->shdr_size);
 
+    // Validate shstrtab offset and size are within file bounds
+    if (shstrtab->sh_offset >= file_size || shstrtab->sh_size > file_size - shstrtab->sh_offset) {
+        return false;
+    }
+
     char *names = (void *)elf + shstrtab->sh_offset;
 
     for (uint16_t i = 0; i < hdr->sh_num; i++) {
         struct elf64_shdr *section = (void *)elf + (hdr->shoff + i * hdr->shdr_size);
 
+        // Validate sh_name is within the string table
+        if (section->sh_name >= shstrtab->sh_size) {
+            continue;
+        }
+
         if (strcmp(&names[section->sh_name], name) == 0) {
+            // Validate section data is within file bounds
+            if (section->sh_offset >= file_size || section->sh_size > file_size - section->sh_offset) {
+                return false;
+            }
+
             if (limit == 0) {
                 *(void **)buffer = ext_mem_alloc(section->sh_size);
                 buffer = *(void **)buffer;
diff --git a/common/lib/elf.h b/common/lib/elf.h
index ef980228..eac3a67b 100644
--- a/common/lib/elf.h
+++ b/common/lib/elf.h
@@ -24,7 +24,7 @@ int elf_bits(uint8_t *elf);
 struct elf_section_hdr_info elf64_section_hdr_info(uint8_t *elf);
 struct elf_section_hdr_info elf32_section_hdr_info(uint8_t *elf);
 
-bool elf64_load_section(uint8_t *elf, void *buffer, const char *name, size_t limit, uint64_t slide);
+bool elf64_load_section(uint8_t *elf, size_t file_size, void *buffer, const char *name, size_t limit, uint64_t slide);
 bool elf64_load(uint8_t *elf, 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);
 
 bool elf32_load_elsewhere(uint8_t *elf, size_t file_size, uint64_t *entry_point,
tab: 248 wrap: offon