lib/elf: Add more and better sanity checks
diff --git a/common/lib/elf.c b/common/lib/elf.c
index 58190976..1fba9e4f 100644
--- a/common/lib/elf.c
+++ b/common/lib/elf.c
@@ -113,6 +113,50 @@ struct elf64_dyn {
uint64_t d_un;
};
+static bool elf32_validate(struct elf32_hdr *hdr) {
+ if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
+ panic(true, "elf: Not a valid ELF file.");
+ }
+
+ if (hdr->ident[EI_DATA] != BITS_LE) {
+ panic(true, "elf: Not a Little-endian ELF file.");
+ }
+
+ if (hdr->machine != ARCH_X86_32) {
+ panic(true, "elf: Not an IA-32 ELF file.");
+ }
+
+ return true;
+}
+
+static bool elf64_validate(struct elf64_hdr *hdr) {
+ if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
+ panic(true, "elf: Not a valid ELF file.");
+ }
+
+ if (hdr->ident[EI_DATA] != BITS_LE) {
+ panic(true, "elf: Not a Little-endian ELF file.");
+ }
+
+#if defined (__x86_64__) || defined (__i386__)
+ if (hdr->machine != ARCH_X86_64) {
+ panic(true, "elf: Not an x86-64 ELF file.");
+ }
+#elif defined (__aarch64__)
+ if (hdr->machine != ARCH_AARCH64) {
+ panic(true, "elf: Not an aarch64 ELF file.");
+ }
+#elif defined (__riscv64)
+ if (hdr->machine != ARCH_RISCV && hdr->ident[EI_CLASS] == ELFCLASS64) {
+ panic(true, "elf: Not a riscv64 ELF file.");
+ }
+#else
+#error Unknown architecture
+#endif
+
+ return true;
+}
+
int elf_bits(uint8_t *elf) {
struct elf64_hdr *hdr = (void *)elf;
@@ -139,6 +183,8 @@ struct elf_section_hdr_info elf64_section_hdr_info(uint8_t *elf) {
struct elf64_hdr *hdr = (void *)elf;
+ elf64_validate(hdr);
+
info.num = hdr->sh_num;
info.section_entry_size = hdr->shdr_size;
info.str_section_idx = hdr->shstrndx;
@@ -152,6 +198,8 @@ struct elf_section_hdr_info elf32_section_hdr_info(uint8_t *elf) {
struct elf32_hdr *hdr = (void *)elf;
+ elf32_validate(hdr);
+
info.num = hdr->sh_num;
info.section_entry_size = hdr->shdr_size;
info.str_section_idx = hdr->shstrndx;
@@ -248,9 +296,8 @@ static bool elf64_apply_relocations(uint8_t *elf, struct elf64_hdr *hdr, void *b
break;
}
- if (rela_ent != sizeof(struct elf64_rela)) {
- print("elf: Unknown sh_entsize for RELA section!\n");
- return false;
+ if (rela_ent < sizeof(struct elf64_rela)) {
+ panic(true, "elf: sh_entsize < sizeof(struct elf64_rela)");
}
for (uint16_t j = 0; j < hdr->ph_num; j++) {
@@ -263,16 +310,26 @@ static bool elf64_apply_relocations(uint8_t *elf, struct elf64_hdr *hdr, void *b
}
}
- for (uint16_t j = 0; j < hdr->ph_num; j++) {
- struct elf64_phdr *_phdr = (void *)elf + (hdr->phoff + j * hdr->phdr_size);
+ if (symtab_ent < sizeof(struct elf64_sym)) {
+ symtab_offset = 0;
+ }
- if (_phdr->p_vaddr <= symtab_offset && _phdr->p_vaddr + _phdr->p_filesz > symtab_offset) {
- symtab_offset -= _phdr->p_vaddr;
- symtab_offset += _phdr->p_offset;
- break;
+ if (symtab_offset != 0) {
+ for (uint16_t j = 0; j < hdr->ph_num; j++) {
+ struct elf64_phdr *_phdr = (void *)elf + (hdr->phoff + j * hdr->phdr_size);
+
+ if (_phdr->p_vaddr <= symtab_offset && _phdr->p_vaddr + _phdr->p_filesz > symtab_offset) {
+ symtab_offset -= _phdr->p_vaddr;
+ symtab_offset += _phdr->p_offset;
+ break;
+ }
}
}
+ if (dt_pltrelsz == 0) {
+ dt_jmprel = 0;
+ }
+
if (dt_jmprel != 0) {
for (uint16_t j = 0; j < hdr->ph_num; j++) {
struct elf64_phdr *_phdr = (void *)elf + (hdr->phoff + j * hdr->phdr_size);
@@ -385,34 +442,7 @@ static bool elf64_apply_relocations(uint8_t *elf, struct elf64_hdr *hdr, void *b
bool elf64_load_section(uint8_t *elf, void *buffer, const char *name, size_t limit, uint64_t slide) {
struct elf64_hdr *hdr = (void *)elf;
- if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
- printv("elf: Not a valid ELF file.\n");
- return false;
- }
-
- if (hdr->ident[EI_DATA] != BITS_LE) {
- printv("elf: Not a Little-endian ELF file.\n");
- return false;
- }
-
-#if defined (__x86_64__) || defined (__i386__)
- if (hdr->machine != ARCH_X86_64) {
- printv("elf: Not an x86-64 ELF file.\n");
- return false;
- }
-#elif defined (__aarch64__)
- if (hdr->machine != ARCH_AARCH64) {
- printv("elf: Not an aarch64 ELF file.\n");
- return false;
- }
-#elif defined (__riscv64)
- if (hdr->machine != ARCH_RISCV && hdr->ident[EI_CLASS] == ELFCLASS64) {
- printv("elf: Not a riscv64 ELF file.\n");
- return false;
- }
-#else
-#error Unknown architecture
-#endif
+ elf64_validate(hdr);
if (hdr->sh_num == 0) {
return false;
@@ -538,30 +568,7 @@ static void elf64_get_ranges(uint8_t *elf, uint64_t slide, struct elf_range **_r
bool elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *_slide, uint32_t alloc_type, bool kaslr, struct elf_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) {
struct elf64_hdr *hdr = (void *)elf;
- if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
- printv("elf: Not a valid ELF file.\n");
- return false;
- }
-
- if (hdr->ident[EI_DATA] != BITS_LE) {
- panic(true, "elf: Not a Little-endian ELF file.\n");
- }
-
-#if defined (__x86_64__) || defined (__i386__)
- if (hdr->machine != ARCH_X86_64) {
- panic(true, "elf: Not an x86-64 ELF file.\n");
- }
-#elif defined (__aarch64__)
- if (hdr->machine != ARCH_AARCH64) {
- panic(true, "elf: Not an aarch64 ELF file.\n");
- }
-#elif defined (__riscv64)
- if (hdr->machine != ARCH_RISCV && hdr->ident[EI_CLASS] == ELFCLASS64) {
- panic(true, "elf: Not a riscv64 ELF file.\n");
- }
-#else
-#error Unknown architecture
-#endif
+ elf64_validate(hdr);
if (is_reloc) {
*is_reloc = false;
@@ -753,20 +760,7 @@ bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
struct elsewhere_range **ranges) {
struct elf32_hdr *hdr = (void *)elf;
- if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
- printv("elf: Not a valid ELF file.\n");
- return false;
- }
-
- if (hdr->ident[EI_DATA] != BITS_LE) {
- printv("elf: Not a Little-endian ELF file.\n");
- return false;
- }
-
- if (hdr->machine != ARCH_X86_32) {
- printv("elf: Not an x86_32 ELF file.\n");
- return false;
- }
+ elf32_validate(hdr);
*entry_point = hdr->entry;
bool entry_adjusted = false;
@@ -831,20 +825,7 @@ bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
struct elsewhere_range **ranges) {
struct elf64_hdr *hdr = (void *)elf;
- if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
- printv("elf: Not a valid ELF file.\n");
- return false;
- }
-
- if (hdr->ident[EI_DATA] != BITS_LE) {
- printv("elf: Not a Little-endian ELF file.\n");
- return false;
- }
-
- if (hdr->machine != ARCH_X86_64) {
- printv("elf: Not an x86-64 ELF file.\n");
- return false;
- }
+ elf64_validate(hdr);
*entry_point = hdr->entry;
bool entry_adjusted = false;
diff --git a/common/protos/limine.c b/common/protos/limine.c
index 1cbdea5e..b63f7ab0 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -330,12 +330,6 @@ noreturn void limine_load(char *config, char *cmdline) {
if (kaslr_s != NULL && strcmp(kaslr_s, "no") == 0)
kaslr = false;
- int bits = elf_bits(kernel);
-
- if (bits == -1 || bits == 32) {
- panic(true, "limine: Kernel in unrecognised format");
- }
-
// ELF loading
uint64_t entry_point = 0;
struct elf_range *ranges;
