:: commit e8689101754a6a5321ce8f4066853e3e9e9e5863

mintsuki <mintsuki@protonmail.com> — 2024-06-09 19:34

parents: fb651eeeb0

lib/elf: Reject relocatable ELFs in elf*_load_elsewhere()

diff --git a/common/lib/elf.c b/common/lib/elf.c
index 4bf0f124..6d7b5c5e 100644
--- a/common/lib/elf.c
+++ b/common/lib/elf.c
@@ -116,6 +116,11 @@ struct elf64_rela {
     uint64_t r_addend;
 };
 
+struct elf32_dyn {
+    uint32_t d_tag;
+    uint32_t d_un;
+};
+
 struct elf64_dyn {
     uint64_t d_tag;
     uint64_t d_un;
@@ -216,6 +221,41 @@ struct elf_section_hdr_info elf32_section_hdr_info(uint8_t *elf) {
     return info;
 }
 
+static bool elf32_is_relocatable(uint8_t *elf, struct elf32_hdr *hdr) {
+    if (hdr->phdr_size < sizeof(struct elf32_phdr)) {
+        panic(true, "elf: phdr_size < sizeof(struct elf32_phdr)");
+    }
+
+    // Find DYN segment
+    for (uint16_t i = 0; i < hdr->ph_num; i++) {
+        struct elf32_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
+
+        if (phdr->p_type != PT_DYNAMIC) {
+            continue;
+        }
+
+        if (hdr->type == ET_DYN) {
+            return true;
+        }
+
+        for (uint16_t j = 0; j < phdr->p_filesz / sizeof(struct elf32_dyn); j++) {
+            struct elf32_dyn *dyn = (void *)elf + (phdr->p_offset + j * sizeof(struct elf32_dyn));
+
+            switch (dyn->d_tag) {
+                case DT_FLAGS_1:
+                    if (dyn->d_un & DF_1_PIE) {
+                        return true;
+                    }
+                    break;
+            }
+        }
+
+        break;
+    }
+
+    return false;
+}
+
 static bool elf64_is_relocatable(uint8_t *elf, struct elf64_hdr *hdr) {
     if (hdr->phdr_size < sizeof(struct elf64_phdr)) {
         panic(true, "elf: phdr_size < sizeof(struct elf64_phdr)");
@@ -873,6 +913,10 @@ bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
 
     elf32_validate(hdr);
 
+    if (elf32_is_relocatable(elf, hdr)) {
+        panic(true, "elf: Cannot load relocatable ELF executables");
+    }
+
     *entry_point = hdr->entry;
     bool entry_adjusted = false;
 
@@ -938,6 +982,10 @@ bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
 
     elf64_validate(hdr);
 
+    if (elf64_is_relocatable(elf, hdr)) {
+        panic(true, "elf: Cannot load relocatable ELF executables");
+    }
+
     *entry_point = hdr->entry;
     bool entry_adjusted = false;
 
tab: 248 wrap: offon