xref: /optee_os/ldelf/ta_elf_rel.c (revision 8bbd9b374a51a1b8617796aae8a70c271543357f)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2019, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <elf32.h>
8 #include <elf64.h>
9 #include <elf_common.h>
10 #include <string.h>
11 #include <tee_api_types.h>
12 #include <util.h>
13 
14 #include "sys.h"
15 #include "ta_elf.h"
16 
17 static uint32_t elf_hash(const char *name)
18 {
19 	const unsigned char *p = (const unsigned char *)name;
20 	uint32_t h = 0;
21 	uint32_t g = 0;
22 
23 	while (*p) {
24 		h = (h << 4) + *p++;
25 		g = h & 0xf0000000;
26 		if (g)
27 			h ^= g >> 24;
28 		h &= ~g;
29 	}
30 	return h;
31 }
32 
33 static bool __resolve_sym(struct ta_elf *elf, unsigned int bind,
34 			  size_t st_shndx, size_t st_name, size_t st_value,
35 			  const char *name, vaddr_t *val)
36 {
37 	if (bind != STB_GLOBAL)
38 		return false;
39 	if (st_shndx == SHN_UNDEF || st_shndx == SHN_XINDEX)
40 		return false;
41 	if (!st_name)
42 		return false;
43 	if (st_name > elf->dynstr_size)
44 		err(TEE_ERROR_BAD_FORMAT, "Symbol out of range");
45 
46 	if (strcmp(name, elf->dynstr + st_name))
47 		return false;
48 
49 	*val = st_value + elf->load_addr;
50 	return true;
51 }
52 
53 TEE_Result ta_elf_resolve_sym(const char *name, vaddr_t *val)
54 {
55 	uint32_t hash = elf_hash(name);
56 	struct ta_elf *elf = NULL;
57 	size_t n = 0;
58 
59 	TAILQ_FOREACH(elf, &main_elf_queue, link) {
60 		/*
61 		 * Using uint32_t here for convenience because both Elf64_Word
62 		 * and Elf32_Word are 32-bit types
63 		 */
64 		uint32_t *hashtab = elf->hashtab;
65 		uint32_t nbuckets = hashtab[0];
66 		uint32_t nchains = hashtab[1];
67 		uint32_t *bucket = &hashtab[2];
68 		uint32_t *chain = &bucket[nbuckets];
69 
70 		if (elf->is_32bit) {
71 			Elf32_Sym *sym = elf->dynsymtab;
72 
73 			for (n = bucket[hash % nbuckets]; n; n = chain[n]) {
74 				assert(n < nchains);
75 				if (__resolve_sym(elf,
76 						  ELF32_ST_BIND(sym[n].st_info),
77 						  sym[n].st_shndx,
78 						  sym[n].st_name,
79 						  sym[n].st_value, name, val))
80 					return TEE_SUCCESS;
81 			}
82 		} else {
83 			Elf64_Sym *sym = elf->dynsymtab;
84 
85 			for (n = bucket[hash % nbuckets]; n; n = chain[n]) {
86 				assert(n < nchains);
87 				if (__resolve_sym(elf,
88 						  ELF64_ST_BIND(sym[n].st_info),
89 						  sym[n].st_shndx,
90 						  sym[n].st_name,
91 						  sym[n].st_value, name, val))
92 					return TEE_SUCCESS;
93 			}
94 		}
95 	}
96 
97 	return TEE_ERROR_ITEM_NOT_FOUND;
98 }
99 
100 static void resolve_sym(const char *name, vaddr_t *val)
101 {
102 	TEE_Result res = ta_elf_resolve_sym(name, val);
103 
104 	if (res)
105 		err(res, "Symbol %s not found", name);
106 }
107 
108 static void e32_process_dyn_rel(const Elf32_Sym *sym_tab, size_t num_syms,
109 				const char *str_tab, size_t str_tab_size,
110 				Elf32_Rel *rel, Elf32_Addr *where)
111 {
112 	size_t sym_idx = 0;
113 	const char *name = NULL;
114 	vaddr_t val = 0;
115 	size_t name_idx = 0;
116 
117 	sym_idx = ELF32_R_SYM(rel->r_info);
118 	assert(sym_idx < num_syms);
119 
120 	name_idx = sym_tab[sym_idx].st_name;
121 	assert(name_idx < str_tab_size);
122 	name = str_tab + name_idx;
123 
124 	resolve_sym(name, &val);
125 	*where = val;
126 }
127 
128 static void e32_relocate(struct ta_elf *elf, unsigned int rel_sidx)
129 {
130 	Elf32_Shdr *shdr = elf->shdr;
131 	Elf32_Rel *rel = NULL;
132 	Elf32_Rel *rel_end = NULL;
133 	size_t sym_tab_idx = 0;
134 	Elf32_Sym *sym_tab = NULL;
135 	size_t num_syms = 0;
136 	size_t sh_end = 0;
137 	const char *str_tab = NULL;
138 	size_t str_tab_size = 0;
139 
140 	assert(shdr[rel_sidx].sh_type == SHT_REL);
141 
142 	assert(shdr[rel_sidx].sh_entsize == sizeof(Elf32_Rel));
143 
144 	sym_tab_idx = shdr[rel_sidx].sh_link;
145 	if (sym_tab_idx) {
146 		size_t str_tab_idx = 0;
147 
148 		assert(sym_tab_idx < elf->e_shnum);
149 
150 		assert(shdr[sym_tab_idx].sh_entsize == sizeof(Elf32_Sym));
151 
152 		/* Check the address is inside ELF memory */
153 		if (ADD_OVERFLOW(shdr[sym_tab_idx].sh_addr,
154 				 shdr[sym_tab_idx].sh_size, &sh_end))
155 			err(TEE_ERROR_SECURITY, "Overflow");
156 		assert(sh_end < (elf->max_addr - elf->load_addr));
157 
158 		sym_tab = (Elf32_Sym *)(elf->load_addr +
159 					shdr[sym_tab_idx].sh_addr);
160 
161 		num_syms = shdr[sym_tab_idx].sh_size / sizeof(Elf32_Sym);
162 
163 		str_tab_idx = shdr[sym_tab_idx].sh_link;
164 		if (str_tab_idx) {
165 			/* Check the address is inside ELF memory */
166 			if (ADD_OVERFLOW(shdr[str_tab_idx].sh_addr,
167 					 shdr[str_tab_idx].sh_size, &sh_end))
168 				err(TEE_ERROR_SECURITY, "Overflow");
169 			assert(sh_end < (elf->max_addr - elf->load_addr));
170 
171 			str_tab = (const char *)(elf->load_addr +
172 						 shdr[str_tab_idx].sh_addr);
173 			str_tab_size = shdr[str_tab_idx].sh_size;
174 		}
175 	}
176 
177 	/* Check the address is inside TA memory */
178 	assert(shdr[rel_sidx].sh_addr < (elf->max_addr - elf->load_addr));
179 	rel = (Elf32_Rel *)(elf->load_addr + shdr[rel_sidx].sh_addr);
180 
181 	/* Check the address is inside TA memory */
182 	if (ADD_OVERFLOW(shdr[rel_sidx].sh_addr, shdr[rel_sidx].sh_size,
183 			 &sh_end))
184 		err(TEE_ERROR_SECURITY, "Overflow");
185 	assert(sh_end < (elf->max_addr - elf->load_addr));
186 	rel_end = rel + shdr[rel_sidx].sh_size / sizeof(Elf32_Rel);
187 	for (; rel < rel_end; rel++) {
188 		Elf32_Addr *where = NULL;
189 		size_t sym_idx = 0;
190 
191 		/* Check the address is inside TA memory */
192 		assert(rel->r_offset < (elf->max_addr - elf->load_addr));
193 		where = (Elf32_Addr *)(elf->load_addr + rel->r_offset);
194 
195 		switch (ELF32_R_TYPE(rel->r_info)) {
196 		case R_ARM_ABS32:
197 			sym_idx = ELF32_R_SYM(rel->r_info);
198 			assert(sym_idx < num_syms);
199 			if (sym_tab[sym_idx].st_shndx == SHN_UNDEF) {
200 				/* Symbol is external */
201 				e32_process_dyn_rel(sym_tab, num_syms, str_tab,
202 						    str_tab_size, rel, where);
203 			} else {
204 				*where += elf->load_addr +
205 					  sym_tab[sym_idx].st_value;
206 			}
207 			break;
208 		case R_ARM_REL32:
209 			sym_idx = ELF32_R_SYM(rel->r_info);
210 			assert(sym_idx < num_syms);
211 			*where += sym_tab[sym_idx].st_value - rel->r_offset;
212 			break;
213 		case R_ARM_RELATIVE:
214 			*where += elf->load_addr;
215 			break;
216 		case R_ARM_GLOB_DAT:
217 		case R_ARM_JUMP_SLOT:
218 			e32_process_dyn_rel(sym_tab, num_syms, str_tab,
219 					    str_tab_size, rel, where);
220 			break;
221 		default:
222 			err(TEE_ERROR_BAD_FORMAT, "Unknown relocation type %d",
223 			     ELF32_R_TYPE(rel->r_info));
224 		}
225 	}
226 }
227 
228 #ifdef ARM64
229 static void e64_process_dyn_rela(const Elf64_Sym *sym_tab, size_t num_syms,
230 				 const char *str_tab, size_t str_tab_size,
231 				 Elf64_Rela *rela, Elf64_Addr *where)
232 {
233 	size_t sym_idx = 0;
234 	const char *name = NULL;
235 	uintptr_t val = 0;
236 	size_t name_idx = 0;
237 
238 	sym_idx = ELF64_R_SYM(rela->r_info);
239 	assert(sym_idx < num_syms);
240 
241 	name_idx = sym_tab[sym_idx].st_name;
242 	assert(name_idx < str_tab_size);
243 	name = str_tab + name_idx;
244 
245 	resolve_sym(name, &val);
246 	*where = val;
247 }
248 
249 static void e64_relocate(struct ta_elf *elf, unsigned int rel_sidx)
250 {
251 	Elf64_Shdr *shdr = elf->shdr;
252 	Elf64_Rela *rela = NULL;
253 	Elf64_Rela *rela_end = NULL;
254 	size_t sym_tab_idx = 0;
255 	Elf64_Sym *sym_tab = NULL;
256 	size_t num_syms = 0;
257 	size_t sh_end = 0;
258 	const char *str_tab = NULL;
259 	size_t str_tab_size = 0;
260 
261 	assert(shdr[rel_sidx].sh_type == SHT_RELA);
262 
263 	assert(shdr[rel_sidx].sh_entsize == sizeof(Elf64_Rela));
264 
265 	sym_tab_idx = shdr[rel_sidx].sh_link;
266 	if (sym_tab_idx) {
267 		size_t str_tab_idx = 0;
268 
269 		assert(sym_tab_idx < elf->e_shnum);
270 
271 		assert(shdr[sym_tab_idx].sh_entsize == sizeof(Elf64_Sym));
272 
273 		/* Check the address is inside TA memory */
274 		if (ADD_OVERFLOW(shdr[sym_tab_idx].sh_addr,
275 				 shdr[sym_tab_idx].sh_size, &sh_end))
276 			err(TEE_ERROR_SECURITY, "Overflow");
277 		assert(sh_end < (elf->max_addr - elf->load_addr));
278 
279 		sym_tab = (Elf64_Sym *)(elf->load_addr +
280 					shdr[sym_tab_idx].sh_addr);
281 
282 		num_syms = shdr[sym_tab_idx].sh_size / sizeof(Elf64_Sym);
283 
284 		str_tab_idx = shdr[sym_tab_idx].sh_link;
285 		if (str_tab_idx) {
286 			/* Check the address is inside ELF memory */
287 			if (ADD_OVERFLOW(shdr[str_tab_idx].sh_addr,
288 					 shdr[str_tab_idx].sh_size, &sh_end))
289 				err(TEE_ERROR_SECURITY, "Overflow");
290 			assert(sh_end < (elf->max_addr - elf->load_addr));
291 
292 			str_tab = (const char *)(elf->load_addr +
293 						 shdr[str_tab_idx].sh_addr);
294 			str_tab_size = shdr[str_tab_idx].sh_size;
295 		}
296 	}
297 
298 	/* Check the address is inside TA memory */
299 	assert(shdr[rel_sidx].sh_addr < (elf->max_addr - elf->load_addr));
300 	rela = (Elf64_Rela *)(elf->load_addr + shdr[rel_sidx].sh_addr);
301 
302 	/* Check the address is inside TA memory */
303 	if (ADD_OVERFLOW(shdr[rel_sidx].sh_addr, shdr[rel_sidx].sh_size,
304 			 &sh_end))
305 		err(TEE_ERROR_SECURITY, "Overflow");
306 	assert(sh_end < (elf->max_addr - elf->load_addr));
307 	rela_end = rela + shdr[rel_sidx].sh_size / sizeof(Elf64_Rela);
308 	for (; rela < rela_end; rela++) {
309 		Elf64_Addr *where = NULL;
310 		size_t sym_idx = 0;
311 
312 		/* Check the address is inside TA memory */
313 		assert(rela->r_offset < (elf->max_addr - elf->load_addr));
314 
315 		where = (Elf64_Addr *)(elf->load_addr + rela->r_offset);
316 
317 		switch (ELF64_R_TYPE(rela->r_info)) {
318 		case R_AARCH64_ABS64:
319 			sym_idx = ELF64_R_SYM(rela->r_info);
320 			assert(sym_idx < num_syms);
321 			if (sym_tab[sym_idx].st_shndx == SHN_UNDEF) {
322 				/* Symbol is external */
323 				e64_process_dyn_rela(sym_tab, num_syms, str_tab,
324 						     str_tab_size, rela, where);
325 			} else {
326 				*where = rela->r_addend + elf->load_addr +
327 					 sym_tab[sym_idx].st_value;
328 			}
329 			break;
330 		case R_AARCH64_RELATIVE:
331 			*where = rela->r_addend + elf->load_addr;
332 			break;
333 		case R_AARCH64_GLOB_DAT:
334 		case R_AARCH64_JUMP_SLOT:
335 			e64_process_dyn_rela(sym_tab, num_syms, str_tab,
336 					     str_tab_size, rela, where);
337 			break;
338 		default:
339 			err(TEE_ERROR_BAD_FORMAT, "Unknown relocation type %zd",
340 			     ELF64_R_TYPE(rela->r_info));
341 		}
342 	}
343 }
344 #else /*ARM64*/
345 static void e64_relocate(struct ta_elf *elf __unused,
346 			 unsigned int rel_sidx __unused)
347 {
348 	err(TEE_ERROR_NOT_SUPPORTED, "arm64 not supported");
349 }
350 #endif /*ARM64*/
351 
352 void ta_elf_relocate(struct ta_elf *elf)
353 {
354 	size_t n = 0;
355 
356 	if (elf->is_32bit) {
357 		Elf32_Shdr *shdr = elf->shdr;
358 
359 		for (n = 0; n < elf->e_shnum; n++)
360 			if (shdr[n].sh_type == SHT_REL)
361 				e32_relocate(elf, n);
362 	} else {
363 		Elf64_Shdr *shdr = elf->shdr;
364 
365 		for (n = 0; n < elf->e_shnum; n++)
366 			if (shdr[n].sh_type == SHT_RELA)
367 				e64_relocate(elf, n);
368 
369 	}
370 }
371