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;
