aboutsummaryrefslogtreecommitdiff
path: root/ldelf
diff options
context:
space:
mode:
authorJens Wiklander <jens.wiklander@linaro.org>2020-03-04 11:02:56 +0100
committerJérôme Forissier <jerome@forissier.org>2020-03-06 10:42:04 +0100
commitbc1d13c122371e8d16aa154f2bde93e5f28a2df9 (patch)
tree7abab276c177c90edc9e028d563839849a230bcf /ldelf
parentce94efefb619f4d10aa95e81c2fe02a7dd03b753 (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.c25
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;