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