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