lib/elf: Validate section header bounds in elf_section_hdr_info functions
diff --git a/common/lib/elf.c b/common/lib/elf.c
index 43cd6d47..200d8dde 100644
--- a/common/lib/elf.c
+++ b/common/lib/elf.c
@@ -208,13 +208,18 @@ int elf_bits(uint8_t *elf, size_t file_size) {
}
}
-struct elf_section_hdr_info elf64_section_hdr_info(uint8_t *elf) {
+struct elf_section_hdr_info elf64_section_hdr_info(uint8_t *elf, size_t file_size) {
struct elf_section_hdr_info info = {0};
struct elf64_hdr *hdr = (void *)elf;
elf64_validate(hdr);
+ if (CHECKED_ADD(CHECKED_MUL(hdr->sh_num, hdr->shdr_size, return info),
+ hdr->shoff, return info) > file_size) {
+ return info;
+ }
+
info.num = hdr->sh_num;
info.section_entry_size = hdr->shdr_size;
info.str_section_idx = hdr->shstrndx;
@@ -223,13 +228,18 @@ struct elf_section_hdr_info elf64_section_hdr_info(uint8_t *elf) {
return info;
}
-struct elf_section_hdr_info elf32_section_hdr_info(uint8_t *elf) {
+struct elf_section_hdr_info elf32_section_hdr_info(uint8_t *elf, size_t file_size) {
struct elf_section_hdr_info info = {0};
struct elf32_hdr *hdr = (void *)elf;
elf32_validate(hdr);
+ if (CHECKED_ADD(CHECKED_MUL(hdr->sh_num, hdr->shdr_size, return info),
+ hdr->shoff, return info) > file_size) {
+ return info;
+ }
+
info.num = hdr->sh_num;
info.section_entry_size = hdr->shdr_size;
info.str_section_idx = hdr->shstrndx;
diff --git a/common/lib/elf.h b/common/lib/elf.h
index 1b9b5888..080694d3 100644
--- a/common/lib/elf.h
+++ b/common/lib/elf.h
@@ -21,8 +21,8 @@ struct elf_section_hdr_info {
int elf_bits(uint8_t *elf, size_t file_size);
-struct elf_section_hdr_info elf64_section_hdr_info(uint8_t *elf);
-struct elf_section_hdr_info elf32_section_hdr_info(uint8_t *elf);
+struct elf_section_hdr_info elf64_section_hdr_info(uint8_t *elf, size_t file_size);
+struct elf_section_hdr_info elf32_section_hdr_info(uint8_t *elf, size_t file_size);
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);
diff --git a/common/protos/multiboot1.c b/common/protos/multiboot1.c
index eed18d81..707fc422 100644
--- a/common/protos/multiboot1.c
+++ b/common/protos/multiboot1.c
@@ -166,14 +166,14 @@ noreturn void multiboot1_load(char *config, char *cmdline) {
if (!elf32_load_elsewhere(kernel, kernel_file_size, &entry_point, &ranges))
panic(true, "multiboot1: ELF32 load failure");
- section_hdr_info = elf32_section_hdr_info(kernel);
+ section_hdr_info = elf32_section_hdr_info(kernel, kernel_file_size);
section_hdr_info_valid = true;
break;
case 64: {
if (!elf64_load_elsewhere(kernel, kernel_file_size, &entry_point, &ranges))
panic(true, "multiboot1: ELF64 load failure");
- section_hdr_info = elf64_section_hdr_info(kernel);
+ section_hdr_info = elf64_section_hdr_info(kernel, kernel_file_size);
section_hdr_info_valid = true;
break;
}
diff --git a/common/protos/multiboot2.c b/common/protos/multiboot2.c
index 088f095e..a0c072b1 100644
--- a/common/protos/multiboot2.c
+++ b/common/protos/multiboot2.c
@@ -362,14 +362,14 @@ noreturn void multiboot2_load(char *config, char* cmdline) {
if (!elf32_load_elsewhere(kernel, kernel_file_size, &e, &ranges))
panic(true, "multiboot2: ELF32 load failure");
- section_hdr_info = elf32_section_hdr_info(kernel);
+ section_hdr_info = elf32_section_hdr_info(kernel, kernel_file_size);
section_hdr_info_valid = true;
break;
case 64: {
if (!elf64_load_elsewhere(kernel, kernel_file_size, &e, &ranges))
panic(true, "multiboot2: ELF64 load failure");
- section_hdr_info = elf64_section_hdr_info(kernel);
+ section_hdr_info = elf64_section_hdr_info(kernel, kernel_file_size);
section_hdr_info_valid = true;
break;
}
