:: commit e3b8f542a2f0f7b91486ce44bdc762c9e4852669

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

parents: 6fa65b6a2c

lib/elf: Reject relocatable ELFs with dynamic entries outside PT_LOAD segments

diff --git a/common/lib/elf.c b/common/lib/elf.c
index 2354f8c0..fab58a08 100644
--- a/common/lib/elf.c
+++ b/common/lib/elf.c
@@ -343,30 +343,41 @@ static bool elf64_apply_relocations(uint8_t *elf, struct elf64_hdr *hdr, void *b
 end_of_pt_segment:
 
     if (rela_offset != 0) {
+        bool rela_translated = false;
         for (uint16_t i = 0; i < hdr->ph_num; i++) {
             struct elf64_phdr *_phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
 
             if (_phdr->p_vaddr <= rela_offset && _phdr->p_vaddr + _phdr->p_filesz > rela_offset) {
                 rela_offset -= _phdr->p_vaddr;
                 rela_offset += _phdr->p_offset;
+                rela_translated = true;
                 break;
             }
         }
+        if (!rela_translated) {
+            panic(true, "elf: RELA vaddr not in any PT_LOAD segment");
+        }
     }
 
     if (relr_offset != 0) {
+        bool relr_translated = false;
         for (uint16_t i = 0; i < hdr->ph_num; i++) {
             struct elf64_phdr *_phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
 
             if (_phdr->p_vaddr <= relr_offset && _phdr->p_vaddr + _phdr->p_filesz > relr_offset) {
                 relr_offset -= _phdr->p_vaddr;
                 relr_offset += _phdr->p_offset;
+                relr_translated = true;
                 break;
             }
         }
+        if (!relr_translated) {
+            panic(true, "elf: RELR vaddr not in any PT_LOAD segment");
+        }
     }
 
     if (symtab_offset != 0) {
+        bool symtab_translated = false;
         for (uint16_t i = 0; i < hdr->ph_num; i++) {
             struct elf64_phdr *_phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
 
@@ -375,12 +386,17 @@ end_of_pt_segment:
                 symtab_size = _phdr->p_filesz - (symtab_offset - _phdr->p_vaddr);
                 symtab_offset -= _phdr->p_vaddr;
                 symtab_offset += _phdr->p_offset;
+                symtab_translated = true;
                 break;
             }
         }
+        if (!symtab_translated) {
+            panic(true, "elf: SYMTAB vaddr not in any PT_LOAD segment");
+        }
     }
 
     if (strtab_offset != 0) {
+        bool strtab_translated = false;
         for (uint16_t i = 0; i < hdr->ph_num; i++) {
             struct elf64_phdr *_phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
 
@@ -389,21 +405,30 @@ end_of_pt_segment:
                 strtab_size = _phdr->p_filesz - (strtab_offset - _phdr->p_vaddr);
                 strtab_offset -= _phdr->p_vaddr;
                 strtab_offset += _phdr->p_offset;
+                strtab_translated = true;
                 break;
             }
         }
+        if (!strtab_translated) {
+            panic(true, "elf: STRTAB vaddr not in any PT_LOAD segment");
+        }
     }
 
     if (dt_jmprel != 0) {
+        bool jmprel_translated = false;
         for (uint16_t i = 0; i < hdr->ph_num; i++) {
             struct elf64_phdr *_phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
 
             if (_phdr->p_vaddr <= dt_jmprel && _phdr->p_vaddr + _phdr->p_filesz > dt_jmprel) {
                 dt_jmprel -= _phdr->p_vaddr;
                 dt_jmprel += _phdr->p_offset;
+                jmprel_translated = true;
                 break;
             }
         }
+        if (!jmprel_translated) {
+            panic(true, "elf: JMPREL vaddr not in any PT_LOAD segment");
+        }
     }
 
     size_t relocs_i = 0;
tab: 248 wrap: offon