xref: /optee_os/ldelf/ta_elf_rel.c (revision cf830b2b674ccc672d0124425714da7cae27c303)
17509ff7cSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
27509ff7cSJens Wiklander /*
37509ff7cSJens Wiklander  * Copyright (c) 2019, Linaro Limited
47509ff7cSJens Wiklander  */
57509ff7cSJens Wiklander 
67509ff7cSJens Wiklander #include <assert.h>
75548a710SJerome Forissier #include <compiler.h>
855e64090SJens Wiklander #include <confine_array_index.h>
97509ff7cSJens Wiklander #include <elf32.h>
107509ff7cSJens Wiklander #include <elf64.h>
117509ff7cSJens Wiklander #include <elf_common.h>
127509ff7cSJens Wiklander #include <string.h>
137509ff7cSJens Wiklander #include <tee_api_types.h>
147509ff7cSJens Wiklander #include <util.h>
157509ff7cSJens Wiklander 
167509ff7cSJens Wiklander #include "sys.h"
177509ff7cSJens Wiklander #include "ta_elf.h"
187509ff7cSJens Wiklander 
199f392760SJerome Forissier static uint32_t elf_hash(const char *name)
209f392760SJerome Forissier {
219f392760SJerome Forissier 	const unsigned char *p = (const unsigned char *)name;
229f392760SJerome Forissier 	uint32_t h = 0;
239f392760SJerome Forissier 	uint32_t g = 0;
249f392760SJerome Forissier 
259f392760SJerome Forissier 	while (*p) {
269f392760SJerome Forissier 		h = (h << 4) + *p++;
279f392760SJerome Forissier 		g = h & 0xf0000000;
289f392760SJerome Forissier 		if (g)
299f392760SJerome Forissier 			h ^= g >> 24;
309f392760SJerome Forissier 		h &= ~g;
319f392760SJerome Forissier 	}
329f392760SJerome Forissier 	return h;
339f392760SJerome Forissier }
349f392760SJerome Forissier 
3597c5ac19SJens Wiklander static bool __resolve_sym(struct ta_elf *elf, unsigned int st_bind,
3697c5ac19SJens Wiklander 			  unsigned int st_type, size_t st_shndx,
3797c5ac19SJens Wiklander 			  size_t st_name, size_t st_value, const char *name,
38*cf830b2bSJerome Forissier 			  vaddr_t *val, bool weak_ok)
397509ff7cSJens Wiklander {
40*cf830b2bSJerome Forissier 	bool bind_ok = false;
41*cf830b2bSJerome Forissier 
427509ff7cSJens Wiklander 	if (!st_name)
437509ff7cSJens Wiklander 		return false;
447509ff7cSJens Wiklander 	if (st_name > elf->dynstr_size)
4597c5ac19SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Symbol name out of range");
467509ff7cSJens Wiklander 	if (strcmp(name, elf->dynstr + st_name))
477509ff7cSJens Wiklander 		return false;
48*cf830b2bSJerome Forissier 	if (st_bind == STB_GLOBAL || (weak_ok && st_bind == STB_WEAK))
49*cf830b2bSJerome Forissier 		bind_ok = true;
50*cf830b2bSJerome Forissier 	if (!bind_ok)
51*cf830b2bSJerome Forissier 		return false;
52*cf830b2bSJerome Forissier 	if (st_bind == STB_WEAK && st_shndx == SHN_UNDEF) {
53*cf830b2bSJerome Forissier 		if (val)
54*cf830b2bSJerome Forissier 			*val = 0;
55*cf830b2bSJerome Forissier 		return true;
56*cf830b2bSJerome Forissier 	}
57*cf830b2bSJerome Forissier 	if (st_shndx == SHN_UNDEF || st_shndx == SHN_XINDEX)
58*cf830b2bSJerome Forissier 		return false;
597509ff7cSJens Wiklander 
6097c5ac19SJens Wiklander 	if (st_value > (elf->max_addr - elf->load_addr))
6197c5ac19SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Symbol location out of range");
6297c5ac19SJens Wiklander 
6397c5ac19SJens Wiklander 	switch (st_type) {
64bb8cd6f0SJerome Forissier 	case STT_NOTYPE:
6597c5ac19SJens Wiklander 	case STT_OBJECT:
6697c5ac19SJens Wiklander 	case STT_FUNC:
677509ff7cSJens Wiklander 		*val = st_value + elf->load_addr;
6897c5ac19SJens Wiklander 		break;
6997c5ac19SJens Wiklander 	default:
7097c5ac19SJens Wiklander 		err(TEE_ERROR_NOT_SUPPORTED, "Symbol type not supported");
7197c5ac19SJens Wiklander 	}
7297c5ac19SJens Wiklander 
737509ff7cSJens Wiklander 	return true;
747509ff7cSJens Wiklander }
757509ff7cSJens Wiklander 
76ebef121cSJerome Forissier static TEE_Result resolve_sym_helper(uint32_t hash, const char *name,
77*cf830b2bSJerome Forissier 				     vaddr_t *val, struct ta_elf *elf,
78*cf830b2bSJerome Forissier 				     bool weak_ok)
797509ff7cSJens Wiklander {
809f392760SJerome Forissier 	/*
819f392760SJerome Forissier 	 * Using uint32_t here for convenience because both Elf64_Word
829f392760SJerome Forissier 	 * and Elf32_Word are 32-bit types
839f392760SJerome Forissier 	 */
849f392760SJerome Forissier 	uint32_t *hashtab = elf->hashtab;
859f392760SJerome Forissier 	uint32_t nbuckets = hashtab[0];
869f392760SJerome Forissier 	uint32_t nchains = hashtab[1];
879f392760SJerome Forissier 	uint32_t *bucket = &hashtab[2];
889f392760SJerome Forissier 	uint32_t *chain = &bucket[nbuckets];
89ebef121cSJerome Forissier 	size_t n = 0;
909f392760SJerome Forissier 
917509ff7cSJens Wiklander 	if (elf->is_32bit) {
927509ff7cSJens Wiklander 		Elf32_Sym *sym = elf->dynsymtab;
937509ff7cSJens Wiklander 
949f392760SJerome Forissier 		for (n = bucket[hash % nbuckets]; n; n = chain[n]) {
958dbe2cbdSJens Wiklander 			if (n >= nchains || n >= elf->num_dynsyms)
965c0860dbSJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
975c0860dbSJens Wiklander 				    "Index out of range");
9855e64090SJens Wiklander 			/*
9955e64090SJens Wiklander 			 * We're loading values from sym[] which later
10055e64090SJens Wiklander 			 * will be used to load something.
10155e64090SJens Wiklander 			 * => Spectre V1 pattern, need to cap the index
10255e64090SJens Wiklander 			 * against speculation.
10355e64090SJens Wiklander 			 */
10455e64090SJens Wiklander 			n = confine_array_index(n, elf->num_dynsyms);
1057509ff7cSJens Wiklander 			if (__resolve_sym(elf,
1067509ff7cSJens Wiklander 					  ELF32_ST_BIND(sym[n].st_info),
10797c5ac19SJens Wiklander 					  ELF32_ST_TYPE(sym[n].st_info),
1087509ff7cSJens Wiklander 					  sym[n].st_shndx,
1097509ff7cSJens Wiklander 					  sym[n].st_name,
110*cf830b2bSJerome Forissier 					  sym[n].st_value, name, val, weak_ok))
111c86f218cSJens Wiklander 				return TEE_SUCCESS;
1127509ff7cSJens Wiklander 		}
1137509ff7cSJens Wiklander 	} else {
1147509ff7cSJens Wiklander 		Elf64_Sym *sym = elf->dynsymtab;
1157509ff7cSJens Wiklander 
1169f392760SJerome Forissier 		for (n = bucket[hash % nbuckets]; n; n = chain[n]) {
1178dbe2cbdSJens Wiklander 			if (n >= nchains || n >= elf->num_dynsyms)
1185c0860dbSJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
1195c0860dbSJens Wiklander 				    "Index out of range");
12055e64090SJens Wiklander 			/*
12155e64090SJens Wiklander 			 * We're loading values from sym[] which later
12255e64090SJens Wiklander 			 * will be used to load something.
12355e64090SJens Wiklander 			 * => Spectre V1 pattern, need to cap the index
12455e64090SJens Wiklander 			 * against speculation.
12555e64090SJens Wiklander 			 */
12655e64090SJens Wiklander 			n = confine_array_index(n, elf->num_dynsyms);
1277509ff7cSJens Wiklander 			if (__resolve_sym(elf,
1287509ff7cSJens Wiklander 					  ELF64_ST_BIND(sym[n].st_info),
12997c5ac19SJens Wiklander 					  ELF64_ST_TYPE(sym[n].st_info),
1307509ff7cSJens Wiklander 					  sym[n].st_shndx,
1317509ff7cSJens Wiklander 					  sym[n].st_name,
132*cf830b2bSJerome Forissier 					  sym[n].st_value, name, val, weak_ok))
133c86f218cSJens Wiklander 				return TEE_SUCCESS;
1347509ff7cSJens Wiklander 		}
1357509ff7cSJens Wiklander 	}
136ebef121cSJerome Forissier 
137ebef121cSJerome Forissier 	return TEE_ERROR_ITEM_NOT_FOUND;
1387509ff7cSJens Wiklander }
139c86f218cSJens Wiklander 
140*cf830b2bSJerome Forissier /*
141*cf830b2bSJerome Forissier  * Look for named symbol in @elf, or all modules if @elf == NULL. Global symbols
142*cf830b2bSJerome Forissier  * are searched first, then weak ones. Last option, when at least one weak but
143*cf830b2bSJerome Forissier  * undefined symbol exists, resolve to zero. Otherwise return
144*cf830b2bSJerome Forissier  * TEE_ERROR_ITEM_NOT_FOUND.
145*cf830b2bSJerome Forissier  */
146ebef121cSJerome Forissier TEE_Result ta_elf_resolve_sym(const char *name, vaddr_t *val,
147ebef121cSJerome Forissier 			      struct ta_elf *elf)
148ebef121cSJerome Forissier {
149ebef121cSJerome Forissier 	uint32_t hash = elf_hash(name);
150ebef121cSJerome Forissier 
151*cf830b2bSJerome Forissier 	if (elf) {
152*cf830b2bSJerome Forissier 		/* Search global symbols */
153*cf830b2bSJerome Forissier 		if (!resolve_sym_helper(hash, name, val, elf,
154*cf830b2bSJerome Forissier 					false /* !weak_ok */))
155ebef121cSJerome Forissier 			return TEE_SUCCESS;
156*cf830b2bSJerome Forissier 		/* Search weak symbols */
157*cf830b2bSJerome Forissier 		if (!resolve_sym_helper(hash, name, val, elf,
158*cf830b2bSJerome Forissier 					true /* weak_ok */))
159*cf830b2bSJerome Forissier 			return TEE_SUCCESS;
160*cf830b2bSJerome Forissier 	}
161*cf830b2bSJerome Forissier 
162*cf830b2bSJerome Forissier 	TAILQ_FOREACH(elf, &main_elf_queue, link) {
163*cf830b2bSJerome Forissier 		if (!resolve_sym_helper(hash, name, val, elf,
164*cf830b2bSJerome Forissier 					false /* !weak_ok */))
165*cf830b2bSJerome Forissier 			return TEE_SUCCESS;
166*cf830b2bSJerome Forissier 		if (!resolve_sym_helper(hash, name, val, elf,
167*cf830b2bSJerome Forissier 					true /* weak_ok */))
168*cf830b2bSJerome Forissier 			return TEE_SUCCESS;
169*cf830b2bSJerome Forissier 	}
170ebef121cSJerome Forissier 
171c86f218cSJens Wiklander 	return TEE_ERROR_ITEM_NOT_FOUND;
172c86f218cSJens Wiklander }
173c86f218cSJens Wiklander 
174c86f218cSJens Wiklander static void resolve_sym(const char *name, vaddr_t *val)
175c86f218cSJens Wiklander {
176ebef121cSJerome Forissier 	TEE_Result res = ta_elf_resolve_sym(name, val, NULL);
177c86f218cSJens Wiklander 
178c86f218cSJens Wiklander 	if (res)
179c86f218cSJens Wiklander 		err(res, "Symbol %s not found", name);
1807509ff7cSJens Wiklander }
1817509ff7cSJens Wiklander 
1827509ff7cSJens Wiklander static void e32_process_dyn_rel(const Elf32_Sym *sym_tab, size_t num_syms,
1837509ff7cSJens Wiklander 				const char *str_tab, size_t str_tab_size,
1847509ff7cSJens Wiklander 				Elf32_Rel *rel, Elf32_Addr *where)
1857509ff7cSJens Wiklander {
1867509ff7cSJens Wiklander 	size_t sym_idx = 0;
1877509ff7cSJens Wiklander 	const char *name = NULL;
1887509ff7cSJens Wiklander 	vaddr_t val = 0;
1897509ff7cSJens Wiklander 	size_t name_idx = 0;
1907509ff7cSJens Wiklander 
1917509ff7cSJens Wiklander 	sym_idx = ELF32_R_SYM(rel->r_info);
192447354c6SJens Wiklander 	if (sym_idx >= num_syms)
193e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Symbol index out of range");
19455e64090SJens Wiklander 	sym_idx = confine_array_index(sym_idx, num_syms);
1957509ff7cSJens Wiklander 
1967509ff7cSJens Wiklander 	name_idx = sym_tab[sym_idx].st_name;
197447354c6SJens Wiklander 	if (name_idx >= str_tab_size)
198e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Name index out of range");
1997509ff7cSJens Wiklander 	name = str_tab + name_idx;
2007509ff7cSJens Wiklander 
2017509ff7cSJens Wiklander 	resolve_sym(name, &val);
2027509ff7cSJens Wiklander 	*where = val;
2037509ff7cSJens Wiklander }
2047509ff7cSJens Wiklander 
2057509ff7cSJens Wiklander static void e32_relocate(struct ta_elf *elf, unsigned int rel_sidx)
2067509ff7cSJens Wiklander {
2077509ff7cSJens Wiklander 	Elf32_Shdr *shdr = elf->shdr;
2087509ff7cSJens Wiklander 	Elf32_Rel *rel = NULL;
2097509ff7cSJens Wiklander 	Elf32_Rel *rel_end = NULL;
2107509ff7cSJens Wiklander 	size_t sym_tab_idx = 0;
2117509ff7cSJens Wiklander 	Elf32_Sym *sym_tab = NULL;
2127509ff7cSJens Wiklander 	size_t num_syms = 0;
2137509ff7cSJens Wiklander 	size_t sh_end = 0;
2147509ff7cSJens Wiklander 	const char *str_tab = NULL;
2157509ff7cSJens Wiklander 	size_t str_tab_size = 0;
2167509ff7cSJens Wiklander 
2177509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_type == SHT_REL);
2187509ff7cSJens Wiklander 
2197509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_entsize == sizeof(Elf32_Rel));
2207509ff7cSJens Wiklander 
2217509ff7cSJens Wiklander 	sym_tab_idx = shdr[rel_sidx].sh_link;
2227509ff7cSJens Wiklander 	if (sym_tab_idx) {
2237509ff7cSJens Wiklander 		size_t str_tab_idx = 0;
2247509ff7cSJens Wiklander 
225447354c6SJens Wiklander 		if (sym_tab_idx >= elf->e_shnum)
226dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB index out of range");
22755e64090SJens Wiklander 		sym_tab_idx = confine_array_index(sym_tab_idx, elf->e_shnum);
2287509ff7cSJens Wiklander 
2297509ff7cSJens Wiklander 		assert(shdr[sym_tab_idx].sh_entsize == sizeof(Elf32_Sym));
2307509ff7cSJens Wiklander 
2317509ff7cSJens Wiklander 		/* Check the address is inside ELF memory */
2327509ff7cSJens Wiklander 		if (ADD_OVERFLOW(shdr[sym_tab_idx].sh_addr,
2337509ff7cSJens Wiklander 				 shdr[sym_tab_idx].sh_size, &sh_end))
234e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Overflow");
235447354c6SJens Wiklander 		if (sh_end >= (elf->max_addr - elf->load_addr))
236dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB out of range");
2377509ff7cSJens Wiklander 
2387509ff7cSJens Wiklander 		sym_tab = (Elf32_Sym *)(elf->load_addr +
2397509ff7cSJens Wiklander 					shdr[sym_tab_idx].sh_addr);
2407509ff7cSJens Wiklander 
2417509ff7cSJens Wiklander 		num_syms = shdr[sym_tab_idx].sh_size / sizeof(Elf32_Sym);
2427509ff7cSJens Wiklander 
2437509ff7cSJens Wiklander 		str_tab_idx = shdr[sym_tab_idx].sh_link;
2447509ff7cSJens Wiklander 		if (str_tab_idx) {
24555e64090SJens Wiklander 			if (str_tab_idx >= elf->e_shnum)
246e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
247dcf64f87SJens Wiklander 				    "STRTAB index out of range");
24855e64090SJens Wiklander 			str_tab_idx = confine_array_index(str_tab_idx,
24955e64090SJens Wiklander 							  elf->e_shnum);
25055e64090SJens Wiklander 
2517509ff7cSJens Wiklander 			/* Check the address is inside ELF memory */
2527509ff7cSJens Wiklander 			if (ADD_OVERFLOW(shdr[str_tab_idx].sh_addr,
2537509ff7cSJens Wiklander 					 shdr[str_tab_idx].sh_size, &sh_end))
254e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT, "Overflow");
255447354c6SJens Wiklander 			if (sh_end >= (elf->max_addr - elf->load_addr))
256e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
257dcf64f87SJens Wiklander 				    "STRTAB out of range");
2587509ff7cSJens Wiklander 
2597509ff7cSJens Wiklander 			str_tab = (const char *)(elf->load_addr +
2607509ff7cSJens Wiklander 						 shdr[str_tab_idx].sh_addr);
2617509ff7cSJens Wiklander 			str_tab_size = shdr[str_tab_idx].sh_size;
2627509ff7cSJens Wiklander 		}
2637509ff7cSJens Wiklander 	}
2647509ff7cSJens Wiklander 
2657509ff7cSJens Wiklander 	/* Check the address is inside TA memory */
266447354c6SJens Wiklander 	if (ADD_OVERFLOW(shdr[rel_sidx].sh_addr,
267447354c6SJens Wiklander 			 shdr[rel_sidx].sh_size, &sh_end))
268e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Overflow");
269447354c6SJens Wiklander 	if (sh_end >= (elf->max_addr - elf->load_addr))
270dcf64f87SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, ".rel.*/REL out of range");
2717509ff7cSJens Wiklander 	rel = (Elf32_Rel *)(elf->load_addr + shdr[rel_sidx].sh_addr);
2727509ff7cSJens Wiklander 
2737509ff7cSJens Wiklander 	rel_end = rel + shdr[rel_sidx].sh_size / sizeof(Elf32_Rel);
2747509ff7cSJens Wiklander 	for (; rel < rel_end; rel++) {
2757509ff7cSJens Wiklander 		Elf32_Addr *where = NULL;
2767509ff7cSJens Wiklander 		size_t sym_idx = 0;
2777509ff7cSJens Wiklander 
2787509ff7cSJens Wiklander 		/* Check the address is inside TA memory */
279447354c6SJens Wiklander 		if (rel->r_offset >= (elf->max_addr - elf->load_addr))
280e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT,
281447354c6SJens Wiklander 			    "Relocation offset out of range");
2827509ff7cSJens Wiklander 		where = (Elf32_Addr *)(elf->load_addr + rel->r_offset);
2837509ff7cSJens Wiklander 
2847509ff7cSJens Wiklander 		switch (ELF32_R_TYPE(rel->r_info)) {
2857509ff7cSJens Wiklander 		case R_ARM_ABS32:
2867509ff7cSJens Wiklander 			sym_idx = ELF32_R_SYM(rel->r_info);
287447354c6SJens Wiklander 			if (sym_idx >= num_syms)
288e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
289447354c6SJens Wiklander 				    "Symbol index out of range");
2907509ff7cSJens Wiklander 			if (sym_tab[sym_idx].st_shndx == SHN_UNDEF) {
2917509ff7cSJens Wiklander 				/* Symbol is external */
2927509ff7cSJens Wiklander 				e32_process_dyn_rel(sym_tab, num_syms, str_tab,
2937509ff7cSJens Wiklander 						    str_tab_size, rel, where);
2947509ff7cSJens Wiklander 			} else {
2957509ff7cSJens Wiklander 				*where += elf->load_addr +
2967509ff7cSJens Wiklander 					  sym_tab[sym_idx].st_value;
2977509ff7cSJens Wiklander 			}
2987509ff7cSJens Wiklander 			break;
2997509ff7cSJens Wiklander 		case R_ARM_REL32:
3007509ff7cSJens Wiklander 			sym_idx = ELF32_R_SYM(rel->r_info);
301447354c6SJens Wiklander 			if (sym_idx >= num_syms)
302e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
303447354c6SJens Wiklander 				    "Symbol index out of range");
3047509ff7cSJens Wiklander 			*where += sym_tab[sym_idx].st_value - rel->r_offset;
3057509ff7cSJens Wiklander 			break;
3067509ff7cSJens Wiklander 		case R_ARM_RELATIVE:
3077509ff7cSJens Wiklander 			*where += elf->load_addr;
3087509ff7cSJens Wiklander 			break;
3097509ff7cSJens Wiklander 		case R_ARM_GLOB_DAT:
3107509ff7cSJens Wiklander 		case R_ARM_JUMP_SLOT:
3117509ff7cSJens Wiklander 			e32_process_dyn_rel(sym_tab, num_syms, str_tab,
3127509ff7cSJens Wiklander 					    str_tab_size, rel, where);
3137509ff7cSJens Wiklander 			break;
3147509ff7cSJens Wiklander 		default:
3157509ff7cSJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Unknown relocation type %d",
3167509ff7cSJens Wiklander 			     ELF32_R_TYPE(rel->r_info));
3177509ff7cSJens Wiklander 		}
3187509ff7cSJens Wiklander 	}
3197509ff7cSJens Wiklander }
3207509ff7cSJens Wiklander 
3217509ff7cSJens Wiklander #ifdef ARM64
3227509ff7cSJens Wiklander static void e64_process_dyn_rela(const Elf64_Sym *sym_tab, size_t num_syms,
3237509ff7cSJens Wiklander 				 const char *str_tab, size_t str_tab_size,
3247509ff7cSJens Wiklander 				 Elf64_Rela *rela, Elf64_Addr *where)
3257509ff7cSJens Wiklander {
3267509ff7cSJens Wiklander 	size_t sym_idx = 0;
3277509ff7cSJens Wiklander 	const char *name = NULL;
3287509ff7cSJens Wiklander 	uintptr_t val = 0;
3297509ff7cSJens Wiklander 	size_t name_idx = 0;
3307509ff7cSJens Wiklander 
3317509ff7cSJens Wiklander 	sym_idx = ELF64_R_SYM(rela->r_info);
332447354c6SJens Wiklander 	if (sym_idx >= num_syms)
333e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Symbol index out of range");
33455e64090SJens Wiklander 	sym_idx = confine_array_index(sym_idx, num_syms);
3357509ff7cSJens Wiklander 
3367509ff7cSJens Wiklander 	name_idx = sym_tab[sym_idx].st_name;
337447354c6SJens Wiklander 	if (name_idx >= str_tab_size)
338e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Name index out of range");
3397509ff7cSJens Wiklander 	name = str_tab + name_idx;
3407509ff7cSJens Wiklander 
3417509ff7cSJens Wiklander 	resolve_sym(name, &val);
3427509ff7cSJens Wiklander 	*where = val;
3437509ff7cSJens Wiklander }
3447509ff7cSJens Wiklander 
3457509ff7cSJens Wiklander static void e64_relocate(struct ta_elf *elf, unsigned int rel_sidx)
3467509ff7cSJens Wiklander {
3477509ff7cSJens Wiklander 	Elf64_Shdr *shdr = elf->shdr;
3487509ff7cSJens Wiklander 	Elf64_Rela *rela = NULL;
3497509ff7cSJens Wiklander 	Elf64_Rela *rela_end = NULL;
3507509ff7cSJens Wiklander 	size_t sym_tab_idx = 0;
3517509ff7cSJens Wiklander 	Elf64_Sym *sym_tab = NULL;
3527509ff7cSJens Wiklander 	size_t num_syms = 0;
3537509ff7cSJens Wiklander 	size_t sh_end = 0;
3547509ff7cSJens Wiklander 	const char *str_tab = NULL;
3557509ff7cSJens Wiklander 	size_t str_tab_size = 0;
3567509ff7cSJens Wiklander 
3577509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_type == SHT_RELA);
3587509ff7cSJens Wiklander 
3597509ff7cSJens Wiklander 	assert(shdr[rel_sidx].sh_entsize == sizeof(Elf64_Rela));
3607509ff7cSJens Wiklander 
3617509ff7cSJens Wiklander 	sym_tab_idx = shdr[rel_sidx].sh_link;
3627509ff7cSJens Wiklander 	if (sym_tab_idx) {
3637509ff7cSJens Wiklander 		size_t str_tab_idx = 0;
3647509ff7cSJens Wiklander 
365447354c6SJens Wiklander 		if (sym_tab_idx >= elf->e_shnum)
366dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB index out of range");
36755e64090SJens Wiklander 		sym_tab_idx = confine_array_index(sym_tab_idx, elf->e_shnum);
3687509ff7cSJens Wiklander 
3697509ff7cSJens Wiklander 		assert(shdr[sym_tab_idx].sh_entsize == sizeof(Elf64_Sym));
3707509ff7cSJens Wiklander 
3717509ff7cSJens Wiklander 		/* Check the address is inside TA memory */
3727509ff7cSJens Wiklander 		if (ADD_OVERFLOW(shdr[sym_tab_idx].sh_addr,
3737509ff7cSJens Wiklander 				 shdr[sym_tab_idx].sh_size, &sh_end))
374e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Overflow");
375447354c6SJens Wiklander 		if (sh_end >= (elf->max_addr - elf->load_addr))
376dcf64f87SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "SYMTAB out of range");
3777509ff7cSJens Wiklander 
3787509ff7cSJens Wiklander 		sym_tab = (Elf64_Sym *)(elf->load_addr +
3797509ff7cSJens Wiklander 					shdr[sym_tab_idx].sh_addr);
3807509ff7cSJens Wiklander 
3817509ff7cSJens Wiklander 		num_syms = shdr[sym_tab_idx].sh_size / sizeof(Elf64_Sym);
3827509ff7cSJens Wiklander 
3837509ff7cSJens Wiklander 		str_tab_idx = shdr[sym_tab_idx].sh_link;
3847509ff7cSJens Wiklander 		if (str_tab_idx) {
38555e64090SJens Wiklander 			if (str_tab_idx >= elf->e_shnum)
386e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
387dcf64f87SJens Wiklander 				    "STRTAB index out of range");
38855e64090SJens Wiklander 			str_tab_idx = confine_array_index(str_tab_idx,
38955e64090SJens Wiklander 							  elf->e_shnum);
39055e64090SJens Wiklander 
3917509ff7cSJens Wiklander 			/* Check the address is inside ELF memory */
3927509ff7cSJens Wiklander 			if (ADD_OVERFLOW(shdr[str_tab_idx].sh_addr,
3937509ff7cSJens Wiklander 					 shdr[str_tab_idx].sh_size, &sh_end))
394e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT, "Overflow");
395447354c6SJens Wiklander 			if (sh_end >= (elf->max_addr - elf->load_addr))
396e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
397dcf64f87SJens Wiklander 				    "STRTAB out of range");
3987509ff7cSJens Wiklander 
3997509ff7cSJens Wiklander 			str_tab = (const char *)(elf->load_addr +
4007509ff7cSJens Wiklander 						 shdr[str_tab_idx].sh_addr);
4017509ff7cSJens Wiklander 			str_tab_size = shdr[str_tab_idx].sh_size;
4027509ff7cSJens Wiklander 		}
4037509ff7cSJens Wiklander 	}
4047509ff7cSJens Wiklander 
4057509ff7cSJens Wiklander 	/* Check the address is inside TA memory */
406447354c6SJens Wiklander 	if (ADD_OVERFLOW(shdr[rel_sidx].sh_addr,
407447354c6SJens Wiklander 			 shdr[rel_sidx].sh_size, &sh_end))
408e97bbbb2SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, "Overflow");
409447354c6SJens Wiklander 	if (sh_end >= (elf->max_addr - elf->load_addr))
410dcf64f87SJens Wiklander 		err(TEE_ERROR_BAD_FORMAT, ".rel.*/REL out of range");
4117509ff7cSJens Wiklander 	rela = (Elf64_Rela *)(elf->load_addr + shdr[rel_sidx].sh_addr);
4127509ff7cSJens Wiklander 
4137509ff7cSJens Wiklander 	rela_end = rela + shdr[rel_sidx].sh_size / sizeof(Elf64_Rela);
4147509ff7cSJens Wiklander 	for (; rela < rela_end; rela++) {
4157509ff7cSJens Wiklander 		Elf64_Addr *where = NULL;
4167509ff7cSJens Wiklander 		size_t sym_idx = 0;
4177509ff7cSJens Wiklander 
4187509ff7cSJens Wiklander 		/* Check the address is inside TA memory */
419447354c6SJens Wiklander 		if (rela->r_offset >= (elf->max_addr - elf->load_addr))
420e97bbbb2SJens Wiklander 			err(TEE_ERROR_BAD_FORMAT,
421447354c6SJens Wiklander 			    "Relocation offset out of range");
4227509ff7cSJens Wiklander 
4237509ff7cSJens Wiklander 		where = (Elf64_Addr *)(elf->load_addr + rela->r_offset);
4247509ff7cSJens Wiklander 
4257509ff7cSJens Wiklander 		switch (ELF64_R_TYPE(rela->r_info)) {
4267509ff7cSJens Wiklander 		case R_AARCH64_ABS64:
4277509ff7cSJens Wiklander 			sym_idx = ELF64_R_SYM(rela->r_info);
428447354c6SJens Wiklander 			if (sym_idx >= num_syms)
429e97bbbb2SJens Wiklander 				err(TEE_ERROR_BAD_FORMAT,
430447354c6SJens Wiklander 				    "Symbol index out of range");
43155e64090SJens Wiklander 			sym_idx = confine_array_index(sym_idx, num_syms);
4327509ff7cSJens Wiklander 			if (sym_tab[sym_idx].st_shndx == SHN_UNDEF) {
4337509ff7cSJens Wiklander 				/* Symbol is external */
4347509ff7cSJens Wiklander 				e64_process_dyn_rela(sym_tab, num_syms, str_tab,
4357509ff7cSJens Wiklander 						     str_tab_size, rela, where);
4367509ff7cSJens Wiklander 			} else {
4377509ff7cSJens Wiklander 				*where = rela->r_addend + elf->load_addr +
4387509ff7cSJens Wiklander 					 sym_tab[sym_idx].st_value;
4397509ff7cSJens Wiklander 			}
4407509ff7cSJens Wiklander 			break;
4417509ff7cSJens Wiklander 		case R_AARCH64_RELATIVE:
4427509ff7cSJens Wiklander 			*where = rela->r_addend + elf->load_addr;
4437509ff7cSJens Wiklander 			break;
4447509ff7cSJens Wiklander 		case R_AARCH64_GLOB_DAT:
4457509ff7cSJens Wiklander 		case R_AARCH64_JUMP_SLOT:
4467509ff7cSJens Wiklander 			e64_process_dyn_rela(sym_tab, num_syms, str_tab,
4477509ff7cSJens Wiklander 					     str_tab_size, rela, where);
4487509ff7cSJens Wiklander 			break;
4497509ff7cSJens Wiklander 		default:
4507509ff7cSJens Wiklander 			err(TEE_ERROR_BAD_FORMAT, "Unknown relocation type %zd",
4517509ff7cSJens Wiklander 			     ELF64_R_TYPE(rela->r_info));
4527509ff7cSJens Wiklander 		}
4537509ff7cSJens Wiklander 	}
4547509ff7cSJens Wiklander }
4557509ff7cSJens Wiklander #else /*ARM64*/
4565548a710SJerome Forissier static void __noreturn e64_relocate(struct ta_elf *elf __unused,
4577509ff7cSJens Wiklander 				    unsigned int rel_sidx __unused)
4587509ff7cSJens Wiklander {
4597509ff7cSJens Wiklander 	err(TEE_ERROR_NOT_SUPPORTED, "arm64 not supported");
4607509ff7cSJens Wiklander }
4617509ff7cSJens Wiklander #endif /*ARM64*/
4627509ff7cSJens Wiklander 
4637509ff7cSJens Wiklander void ta_elf_relocate(struct ta_elf *elf)
4647509ff7cSJens Wiklander {
4657509ff7cSJens Wiklander 	size_t n = 0;
4667509ff7cSJens Wiklander 
4677509ff7cSJens Wiklander 	if (elf->is_32bit) {
4687509ff7cSJens Wiklander 		Elf32_Shdr *shdr = elf->shdr;
4697509ff7cSJens Wiklander 
4707509ff7cSJens Wiklander 		for (n = 0; n < elf->e_shnum; n++)
4717509ff7cSJens Wiklander 			if (shdr[n].sh_type == SHT_REL)
4727509ff7cSJens Wiklander 				e32_relocate(elf, n);
4737509ff7cSJens Wiklander 	} else {
4747509ff7cSJens Wiklander 		Elf64_Shdr *shdr = elf->shdr;
4757509ff7cSJens Wiklander 
4767509ff7cSJens Wiklander 		for (n = 0; n < elf->e_shnum; n++)
4777509ff7cSJens Wiklander 			if (shdr[n].sh_type == SHT_RELA)
4787509ff7cSJens Wiklander 				e64_relocate(elf, n);
4797509ff7cSJens Wiklander 
4807509ff7cSJens Wiklander 	}
4817509ff7cSJens Wiklander }
482