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