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