diff options
author | Jens Wiklander <jens.wiklander@linaro.org> | 2020-03-04 11:02:56 +0100 |
---|---|---|
committer | Jérôme Forissier <jerome@forissier.org> | 2020-03-06 10:42:04 +0100 |
commit | bc1d13c122371e8d16aa154f2bde93e5f28a2df9 (patch) | |
tree | 7abab276c177c90edc9e028d563839849a230bcf /ldelf | |
parent | ce94efefb619f4d10aa95e81c2fe02a7dd03b753 (diff) |
ldelf: check that PT_DYNAMIC is in range before use
Adds checks that the ELF program header PT_DYNAMIC is in range of the
loaded ELF before they are used. This fixes an error where a malformed
ELF may cause the loader to read data from other ELF or from the loader
itself.
Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
Reported-by: Martijn Bogaard <martijn@riscure.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Diffstat (limited to 'ldelf')
-rw-r--r-- | ldelf/ta_elf.c | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/ldelf/ta_elf.c b/ldelf/ta_elf.c index 5c2a2566..4ce238c9 100644 --- a/ldelf/ta_elf.c +++ b/ldelf/ta_elf.c @@ -18,6 +18,7 @@ #include <tee_internal_api_extensions.h> #include <user_ta_header.h> #include <utee_syscalls.h> +#include <util.h> #include "sys.h" #include "ta_elf.h" @@ -126,6 +127,24 @@ static TEE_Result e64_parse_ehdr(struct ta_elf *elf __unused, } #endif /*ARM64*/ +static void check_phdr_in_range(struct ta_elf *elf, unsigned int type, + vaddr_t addr, size_t memsz) +{ + vaddr_t max_addr = 0; + + if (ADD_OVERFLOW(addr, memsz, &max_addr)) + err(TEE_ERROR_BAD_FORMAT, "Program header %#x overflow", type); + + /* + * elf->load_addr and elf->max_addr are both using the + * final virtual addresses, while this program header is + * relative to 0. + */ + if (max_addr > elf->max_addr - elf->load_addr) + err(TEE_ERROR_BAD_FORMAT, "Program header %#x out of bounds", + type); +} + static void read_dyn(struct ta_elf *elf, vaddr_t addr, size_t idx, unsigned int *tag, size_t *val) { @@ -154,6 +173,8 @@ static void save_hashtab_from_segment(struct ta_elf *elf, unsigned int type, if (type != PT_DYNAMIC) return; + check_phdr_in_range(elf, type, addr, memsz); + if (elf->is_32bit) dyn_entsize = sizeof(Elf32_Dyn); else @@ -711,6 +732,8 @@ static void add_deps_from_segment(struct ta_elf *elf, unsigned int type, if (type != PT_DYNAMIC) return; + check_phdr_in_range(elf, type, addr, memsz); + if (elf->is_32bit) dyn_entsize = sizeof(Elf32_Dyn); else @@ -1216,6 +1239,8 @@ static void get_init_fini_array(struct ta_elf *elf, unsigned int type, assert(type == PT_DYNAMIC); + check_phdr_in_range(elf, type, addr, memsz); + if (elf->is_32bit) { dyn_entsize = sizeof(Elf32_Dyn); addrsz = 4; |