17509ff7cSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause 27509ff7cSJens Wiklander /* 37509ff7cSJens Wiklander * Copyright (c) 2019, Linaro Limited 47509ff7cSJens Wiklander */ 57509ff7cSJens Wiklander 67509ff7cSJens Wiklander #include <assert.h> 75548a710SJerome Forissier #include <compiler.h> 855e64090SJens Wiklander #include <confine_array_index.h> 97509ff7cSJens Wiklander #include <elf32.h> 107509ff7cSJens Wiklander #include <elf64.h> 117509ff7cSJens Wiklander #include <elf_common.h> 127509ff7cSJens Wiklander #include <string.h> 137509ff7cSJens Wiklander #include <tee_api_types.h> 147509ff7cSJens Wiklander #include <util.h> 157509ff7cSJens Wiklander 167509ff7cSJens Wiklander #include "sys.h" 177509ff7cSJens Wiklander #include "ta_elf.h" 187509ff7cSJens Wiklander 199f392760SJerome Forissier static uint32_t elf_hash(const char *name) 209f392760SJerome Forissier { 219f392760SJerome Forissier const unsigned char *p = (const unsigned char *)name; 229f392760SJerome Forissier uint32_t h = 0; 239f392760SJerome Forissier uint32_t g = 0; 249f392760SJerome Forissier 259f392760SJerome Forissier while (*p) { 269f392760SJerome Forissier h = (h << 4) + *p++; 279f392760SJerome Forissier g = h & 0xf0000000; 289f392760SJerome Forissier if (g) 299f392760SJerome Forissier h ^= g >> 24; 309f392760SJerome Forissier h &= ~g; 319f392760SJerome Forissier } 329f392760SJerome Forissier return h; 339f392760SJerome Forissier } 349f392760SJerome Forissier 3597c5ac19SJens Wiklander static bool __resolve_sym(struct ta_elf *elf, unsigned int st_bind, 3697c5ac19SJens Wiklander unsigned int st_type, size_t st_shndx, 3797c5ac19SJens Wiklander size_t st_name, size_t st_value, const char *name, 38cf830b2bSJerome Forissier vaddr_t *val, bool weak_ok) 397509ff7cSJens Wiklander { 40cf830b2bSJerome Forissier bool bind_ok = false; 41cf830b2bSJerome Forissier 427509ff7cSJens Wiklander if (!st_name) 437509ff7cSJens Wiklander return false; 447509ff7cSJens Wiklander if (st_name > elf->dynstr_size) 4597c5ac19SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Symbol name out of range"); 467509ff7cSJens Wiklander if (strcmp(name, elf->dynstr + st_name)) 477509ff7cSJens Wiklander return false; 48cf830b2bSJerome Forissier if (st_bind == STB_GLOBAL || (weak_ok && st_bind == STB_WEAK)) 49cf830b2bSJerome Forissier bind_ok = true; 50cf830b2bSJerome Forissier if (!bind_ok) 51cf830b2bSJerome Forissier return false; 52cf830b2bSJerome Forissier if (st_bind == STB_WEAK && st_shndx == SHN_UNDEF) { 53cf830b2bSJerome Forissier if (val) 54cf830b2bSJerome Forissier *val = 0; 55cf830b2bSJerome Forissier return true; 56cf830b2bSJerome Forissier } 57cf830b2bSJerome Forissier if (st_shndx == SHN_UNDEF || st_shndx == SHN_XINDEX) 58cf830b2bSJerome Forissier return false; 597509ff7cSJens Wiklander 6097c5ac19SJens Wiklander switch (st_type) { 61bb8cd6f0SJerome Forissier case STT_NOTYPE: 6297c5ac19SJens Wiklander case STT_OBJECT: 6397c5ac19SJens Wiklander case STT_FUNC: 64c88ba125SJerome Forissier if (st_value > (elf->max_addr - elf->load_addr)) 65c88ba125SJerome Forissier err(TEE_ERROR_BAD_FORMAT, 66c88ba125SJerome Forissier "Symbol location out of range"); 67c88ba125SJerome Forissier if (val) 687509ff7cSJens Wiklander *val = st_value + elf->load_addr; 6997c5ac19SJens Wiklander break; 70c88ba125SJerome Forissier case STT_TLS: 71c88ba125SJerome Forissier if (val) 72c88ba125SJerome Forissier *val = st_value; 73c88ba125SJerome Forissier break; 7497c5ac19SJens Wiklander default: 7597c5ac19SJens Wiklander err(TEE_ERROR_NOT_SUPPORTED, "Symbol type not supported"); 7697c5ac19SJens Wiklander } 7797c5ac19SJens Wiklander 787509ff7cSJens Wiklander return true; 797509ff7cSJens Wiklander } 807509ff7cSJens Wiklander 81ebef121cSJerome Forissier static TEE_Result resolve_sym_helper(uint32_t hash, const char *name, 82cf830b2bSJerome Forissier vaddr_t *val, struct ta_elf *elf, 83cf830b2bSJerome Forissier bool weak_ok) 847509ff7cSJens Wiklander { 859f392760SJerome Forissier /* 869f392760SJerome Forissier * Using uint32_t here for convenience because both Elf64_Word 879f392760SJerome Forissier * and Elf32_Word are 32-bit types 889f392760SJerome Forissier */ 899f392760SJerome Forissier uint32_t *hashtab = elf->hashtab; 909f392760SJerome Forissier uint32_t nbuckets = hashtab[0]; 919f392760SJerome Forissier uint32_t nchains = hashtab[1]; 929f392760SJerome Forissier uint32_t *bucket = &hashtab[2]; 939f392760SJerome Forissier uint32_t *chain = &bucket[nbuckets]; 94ebef121cSJerome Forissier size_t n = 0; 959f392760SJerome Forissier 967509ff7cSJens Wiklander if (elf->is_32bit) { 977509ff7cSJens Wiklander Elf32_Sym *sym = elf->dynsymtab; 987509ff7cSJens Wiklander 999f392760SJerome Forissier for (n = bucket[hash % nbuckets]; n; n = chain[n]) { 1008dbe2cbdSJens Wiklander if (n >= nchains || n >= elf->num_dynsyms) 1015c0860dbSJens Wiklander err(TEE_ERROR_BAD_FORMAT, 1025c0860dbSJens Wiklander "Index out of range"); 10355e64090SJens Wiklander /* 10455e64090SJens Wiklander * We're loading values from sym[] which later 10555e64090SJens Wiklander * will be used to load something. 10655e64090SJens Wiklander * => Spectre V1 pattern, need to cap the index 10755e64090SJens Wiklander * against speculation. 10855e64090SJens Wiklander */ 10955e64090SJens Wiklander n = confine_array_index(n, elf->num_dynsyms); 1107509ff7cSJens Wiklander if (__resolve_sym(elf, 1117509ff7cSJens Wiklander ELF32_ST_BIND(sym[n].st_info), 11297c5ac19SJens Wiklander ELF32_ST_TYPE(sym[n].st_info), 1137509ff7cSJens Wiklander sym[n].st_shndx, 1147509ff7cSJens Wiklander sym[n].st_name, 115cf830b2bSJerome Forissier sym[n].st_value, name, val, weak_ok)) 116c86f218cSJens Wiklander return TEE_SUCCESS; 1177509ff7cSJens Wiklander } 1187509ff7cSJens Wiklander } else { 1197509ff7cSJens Wiklander Elf64_Sym *sym = elf->dynsymtab; 1207509ff7cSJens Wiklander 1219f392760SJerome Forissier for (n = bucket[hash % nbuckets]; n; n = chain[n]) { 1228dbe2cbdSJens Wiklander if (n >= nchains || n >= elf->num_dynsyms) 1235c0860dbSJens Wiklander err(TEE_ERROR_BAD_FORMAT, 1245c0860dbSJens Wiklander "Index out of range"); 12555e64090SJens Wiklander /* 12655e64090SJens Wiklander * We're loading values from sym[] which later 12755e64090SJens Wiklander * will be used to load something. 12855e64090SJens Wiklander * => Spectre V1 pattern, need to cap the index 12955e64090SJens Wiklander * against speculation. 13055e64090SJens Wiklander */ 13155e64090SJens Wiklander n = confine_array_index(n, elf->num_dynsyms); 1327509ff7cSJens Wiklander if (__resolve_sym(elf, 1337509ff7cSJens Wiklander ELF64_ST_BIND(sym[n].st_info), 13497c5ac19SJens Wiklander ELF64_ST_TYPE(sym[n].st_info), 1357509ff7cSJens Wiklander sym[n].st_shndx, 1367509ff7cSJens Wiklander sym[n].st_name, 137cf830b2bSJerome Forissier sym[n].st_value, name, val, weak_ok)) 138c86f218cSJens Wiklander return TEE_SUCCESS; 1397509ff7cSJens Wiklander } 1407509ff7cSJens Wiklander } 141ebef121cSJerome Forissier 142ebef121cSJerome Forissier return TEE_ERROR_ITEM_NOT_FOUND; 1437509ff7cSJens Wiklander } 144c86f218cSJens Wiklander 145cf830b2bSJerome Forissier /* 146cf830b2bSJerome Forissier * Look for named symbol in @elf, or all modules if @elf == NULL. Global symbols 147cf830b2bSJerome Forissier * are searched first, then weak ones. Last option, when at least one weak but 148cf830b2bSJerome Forissier * undefined symbol exists, resolve to zero. Otherwise return 149cf830b2bSJerome Forissier * TEE_ERROR_ITEM_NOT_FOUND. 150c88ba125SJerome Forissier * @val (if != 0) receives the symbol value 151c88ba125SJerome Forissier * @found_elf (if != 0) receives the module where the symbol is found 152cf830b2bSJerome Forissier */ 153ebef121cSJerome Forissier TEE_Result ta_elf_resolve_sym(const char *name, vaddr_t *val, 154c88ba125SJerome Forissier struct ta_elf **found_elf, 155ebef121cSJerome Forissier struct ta_elf *elf) 156ebef121cSJerome Forissier { 157ebef121cSJerome Forissier uint32_t hash = elf_hash(name); 158ebef121cSJerome Forissier 159cf830b2bSJerome Forissier if (elf) { 160cf830b2bSJerome Forissier /* Search global symbols */ 161cf830b2bSJerome Forissier if (!resolve_sym_helper(hash, name, val, elf, 162cf830b2bSJerome Forissier false /* !weak_ok */)) 163c88ba125SJerome Forissier goto success; 164cf830b2bSJerome Forissier /* Search weak symbols */ 165cf830b2bSJerome Forissier if (!resolve_sym_helper(hash, name, val, elf, 166cf830b2bSJerome Forissier true /* weak_ok */)) 167c88ba125SJerome Forissier goto success; 168cf830b2bSJerome Forissier } 169cf830b2bSJerome Forissier 170cf830b2bSJerome Forissier TAILQ_FOREACH(elf, &main_elf_queue, link) { 171cf830b2bSJerome Forissier if (!resolve_sym_helper(hash, name, val, elf, 172cf830b2bSJerome Forissier false /* !weak_ok */)) 173c88ba125SJerome Forissier goto success; 174cf830b2bSJerome Forissier if (!resolve_sym_helper(hash, name, val, elf, 175cf830b2bSJerome Forissier true /* weak_ok */)) 176c88ba125SJerome Forissier goto success; 177cf830b2bSJerome Forissier } 178ebef121cSJerome Forissier 179c86f218cSJens Wiklander return TEE_ERROR_ITEM_NOT_FOUND; 180c88ba125SJerome Forissier 181c88ba125SJerome Forissier success: 182c88ba125SJerome Forissier if (found_elf) 183c88ba125SJerome Forissier *found_elf = elf; 184c88ba125SJerome Forissier return TEE_SUCCESS; 185c86f218cSJens Wiklander } 186c86f218cSJens Wiklander 187c88ba125SJerome Forissier static void e32_get_sym_name(const Elf32_Sym *sym_tab, size_t num_syms, 1887509ff7cSJens Wiklander const char *str_tab, size_t str_tab_size, 189*c44d734bSJerome Forissier Elf32_Rel *rel, const char **name, 190*c44d734bSJerome Forissier bool *weak_undef) 1917509ff7cSJens Wiklander { 1927509ff7cSJens Wiklander size_t sym_idx = 0; 1937509ff7cSJens Wiklander size_t name_idx = 0; 1947509ff7cSJens Wiklander 1957509ff7cSJens Wiklander sym_idx = ELF32_R_SYM(rel->r_info); 196447354c6SJens Wiklander if (sym_idx >= num_syms) 197e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Symbol index out of range"); 19855e64090SJens Wiklander sym_idx = confine_array_index(sym_idx, num_syms); 1997509ff7cSJens Wiklander 2007509ff7cSJens Wiklander name_idx = sym_tab[sym_idx].st_name; 201447354c6SJens Wiklander if (name_idx >= str_tab_size) 202e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Name index out of range"); 203c88ba125SJerome Forissier *name = str_tab + name_idx; 204*c44d734bSJerome Forissier 205*c44d734bSJerome Forissier if (!weak_undef) 206*c44d734bSJerome Forissier return; 207*c44d734bSJerome Forissier if (sym_tab[sym_idx].st_shndx == SHN_UNDEF && 208*c44d734bSJerome Forissier ELF32_ST_BIND(sym_tab[sym_idx].st_info) == STB_WEAK) 209*c44d734bSJerome Forissier *weak_undef = true; 210*c44d734bSJerome Forissier else 211*c44d734bSJerome Forissier *weak_undef = false; 212c88ba125SJerome Forissier } 2137509ff7cSJens Wiklander 214*c44d734bSJerome Forissier static void resolve_sym(const char *name, vaddr_t *val, struct ta_elf **mod, 215*c44d734bSJerome Forissier bool err_if_not_found) 216c88ba125SJerome Forissier { 217c88ba125SJerome Forissier TEE_Result res = ta_elf_resolve_sym(name, val, mod, NULL); 218c88ba125SJerome Forissier 219*c44d734bSJerome Forissier if (res) { 220*c44d734bSJerome Forissier if (err_if_not_found) 221c88ba125SJerome Forissier err(res, "Symbol %s not found", name); 222*c44d734bSJerome Forissier else 223*c44d734bSJerome Forissier *val = 0; 224*c44d734bSJerome Forissier } 225c88ba125SJerome Forissier } 226c88ba125SJerome Forissier 227c88ba125SJerome Forissier static void e32_process_dyn_rel(const Elf32_Sym *sym_tab, size_t num_syms, 228c88ba125SJerome Forissier const char *str_tab, size_t str_tab_size, 229c88ba125SJerome Forissier Elf32_Rel *rel, Elf32_Addr *where) 230c88ba125SJerome Forissier { 231c88ba125SJerome Forissier const char *name = NULL; 232c88ba125SJerome Forissier vaddr_t val = 0; 233*c44d734bSJerome Forissier bool weak_undef = false; 234c88ba125SJerome Forissier 235*c44d734bSJerome Forissier e32_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rel, &name, 236*c44d734bSJerome Forissier &weak_undef); 237*c44d734bSJerome Forissier resolve_sym(name, &val, NULL, !weak_undef); 2387509ff7cSJens Wiklander *where = val; 2397509ff7cSJens Wiklander } 2407509ff7cSJens Wiklander 241c88ba125SJerome Forissier static void e32_tls_get_module(const Elf32_Sym *sym_tab, size_t num_syms, 242c88ba125SJerome Forissier const char *str_tab, size_t str_tab_size, 243c88ba125SJerome Forissier Elf32_Rel *rel, struct ta_elf **mod) 244c88ba125SJerome Forissier { 245c88ba125SJerome Forissier const char *name = NULL; 246c88ba125SJerome Forissier size_t sym_idx = 0; 247c88ba125SJerome Forissier 248c88ba125SJerome Forissier sym_idx = ELF32_R_SYM(rel->r_info); 249c88ba125SJerome Forissier if (sym_idx >= num_syms) 250c88ba125SJerome Forissier err(TEE_ERROR_BAD_FORMAT, "Symbol index out of range"); 251c88ba125SJerome Forissier sym_idx = confine_array_index(sym_idx, num_syms); 252c88ba125SJerome Forissier if (!sym_idx || sym_tab[sym_idx].st_shndx != SHN_UNDEF) { 253c88ba125SJerome Forissier /* No symbol, or symbol is defined in current module */ 254c88ba125SJerome Forissier return; 255c88ba125SJerome Forissier } 256c88ba125SJerome Forissier 257*c44d734bSJerome Forissier e32_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rel, &name, 258*c44d734bSJerome Forissier NULL); 259*c44d734bSJerome Forissier resolve_sym(name, NULL, mod, false); 260c88ba125SJerome Forissier } 261c88ba125SJerome Forissier 262c88ba125SJerome Forissier static void e32_tls_resolve(const Elf32_Sym *sym_tab, size_t num_syms, 263c88ba125SJerome Forissier const char *str_tab, size_t str_tab_size, 264c88ba125SJerome Forissier Elf32_Rel *rel, vaddr_t *val) 265c88ba125SJerome Forissier { 266c88ba125SJerome Forissier const char *name = NULL; 267c88ba125SJerome Forissier 268*c44d734bSJerome Forissier e32_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rel, &name, 269*c44d734bSJerome Forissier NULL); 270*c44d734bSJerome Forissier resolve_sym(name, val, NULL, false); 271c88ba125SJerome Forissier } 272c88ba125SJerome Forissier 2737509ff7cSJens Wiklander static void e32_relocate(struct ta_elf *elf, unsigned int rel_sidx) 2747509ff7cSJens Wiklander { 2757509ff7cSJens Wiklander Elf32_Shdr *shdr = elf->shdr; 2767509ff7cSJens Wiklander Elf32_Rel *rel = NULL; 2777509ff7cSJens Wiklander Elf32_Rel *rel_end = NULL; 2787509ff7cSJens Wiklander size_t sym_tab_idx = 0; 2797509ff7cSJens Wiklander Elf32_Sym *sym_tab = NULL; 2807509ff7cSJens Wiklander size_t num_syms = 0; 2817509ff7cSJens Wiklander size_t sh_end = 0; 2827509ff7cSJens Wiklander const char *str_tab = NULL; 2837509ff7cSJens Wiklander size_t str_tab_size = 0; 2847509ff7cSJens Wiklander 2857509ff7cSJens Wiklander assert(shdr[rel_sidx].sh_type == SHT_REL); 2867509ff7cSJens Wiklander 2877509ff7cSJens Wiklander assert(shdr[rel_sidx].sh_entsize == sizeof(Elf32_Rel)); 2887509ff7cSJens Wiklander 2897509ff7cSJens Wiklander sym_tab_idx = shdr[rel_sidx].sh_link; 2907509ff7cSJens Wiklander if (sym_tab_idx) { 2917509ff7cSJens Wiklander size_t str_tab_idx = 0; 2927509ff7cSJens Wiklander 293447354c6SJens Wiklander if (sym_tab_idx >= elf->e_shnum) 294dcf64f87SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "SYMTAB index out of range"); 29555e64090SJens Wiklander sym_tab_idx = confine_array_index(sym_tab_idx, elf->e_shnum); 2967509ff7cSJens Wiklander 2977509ff7cSJens Wiklander assert(shdr[sym_tab_idx].sh_entsize == sizeof(Elf32_Sym)); 2987509ff7cSJens Wiklander 2997509ff7cSJens Wiklander /* Check the address is inside ELF memory */ 3007509ff7cSJens Wiklander if (ADD_OVERFLOW(shdr[sym_tab_idx].sh_addr, 3017509ff7cSJens Wiklander shdr[sym_tab_idx].sh_size, &sh_end)) 302e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Overflow"); 303447354c6SJens Wiklander if (sh_end >= (elf->max_addr - elf->load_addr)) 304dcf64f87SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "SYMTAB out of range"); 3057509ff7cSJens Wiklander 3067509ff7cSJens Wiklander sym_tab = (Elf32_Sym *)(elf->load_addr + 3077509ff7cSJens Wiklander shdr[sym_tab_idx].sh_addr); 3087509ff7cSJens Wiklander 3097509ff7cSJens Wiklander num_syms = shdr[sym_tab_idx].sh_size / sizeof(Elf32_Sym); 3107509ff7cSJens Wiklander 3117509ff7cSJens Wiklander str_tab_idx = shdr[sym_tab_idx].sh_link; 3127509ff7cSJens Wiklander if (str_tab_idx) { 31355e64090SJens Wiklander if (str_tab_idx >= elf->e_shnum) 314e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, 315dcf64f87SJens Wiklander "STRTAB index out of range"); 31655e64090SJens Wiklander str_tab_idx = confine_array_index(str_tab_idx, 31755e64090SJens Wiklander elf->e_shnum); 31855e64090SJens Wiklander 3197509ff7cSJens Wiklander /* Check the address is inside ELF memory */ 3207509ff7cSJens Wiklander if (ADD_OVERFLOW(shdr[str_tab_idx].sh_addr, 3217509ff7cSJens Wiklander shdr[str_tab_idx].sh_size, &sh_end)) 322e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Overflow"); 323447354c6SJens Wiklander if (sh_end >= (elf->max_addr - elf->load_addr)) 324e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, 325dcf64f87SJens Wiklander "STRTAB out of range"); 3267509ff7cSJens Wiklander 3277509ff7cSJens Wiklander str_tab = (const char *)(elf->load_addr + 3287509ff7cSJens Wiklander shdr[str_tab_idx].sh_addr); 3297509ff7cSJens Wiklander str_tab_size = shdr[str_tab_idx].sh_size; 3307509ff7cSJens Wiklander } 3317509ff7cSJens Wiklander } 3327509ff7cSJens Wiklander 3337509ff7cSJens Wiklander /* Check the address is inside TA memory */ 334447354c6SJens Wiklander if (ADD_OVERFLOW(shdr[rel_sidx].sh_addr, 335447354c6SJens Wiklander shdr[rel_sidx].sh_size, &sh_end)) 336e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Overflow"); 337447354c6SJens Wiklander if (sh_end >= (elf->max_addr - elf->load_addr)) 338dcf64f87SJens Wiklander err(TEE_ERROR_BAD_FORMAT, ".rel.*/REL out of range"); 3397509ff7cSJens Wiklander rel = (Elf32_Rel *)(elf->load_addr + shdr[rel_sidx].sh_addr); 3407509ff7cSJens Wiklander 3417509ff7cSJens Wiklander rel_end = rel + shdr[rel_sidx].sh_size / sizeof(Elf32_Rel); 3427509ff7cSJens Wiklander for (; rel < rel_end; rel++) { 343c88ba125SJerome Forissier struct ta_elf *mod = NULL; 3447509ff7cSJens Wiklander Elf32_Addr *where = NULL; 3457509ff7cSJens Wiklander size_t sym_idx = 0; 346c88ba125SJerome Forissier vaddr_t val = 0; 3477509ff7cSJens Wiklander 3487509ff7cSJens Wiklander /* Check the address is inside TA memory */ 349447354c6SJens Wiklander if (rel->r_offset >= (elf->max_addr - elf->load_addr)) 350e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, 351447354c6SJens Wiklander "Relocation offset out of range"); 3527509ff7cSJens Wiklander where = (Elf32_Addr *)(elf->load_addr + rel->r_offset); 3537509ff7cSJens Wiklander 3547509ff7cSJens Wiklander switch (ELF32_R_TYPE(rel->r_info)) { 355f104c8eeSEtienne Carriere case R_ARM_NONE: 356f104c8eeSEtienne Carriere /* 357f104c8eeSEtienne Carriere * One would expect linker prevents such useless entry 358f104c8eeSEtienne Carriere * in the relocation table. We still handle this type 359f104c8eeSEtienne Carriere * here in case such entries exist. 360f104c8eeSEtienne Carriere */ 361f104c8eeSEtienne Carriere break; 3627509ff7cSJens Wiklander case R_ARM_ABS32: 3637509ff7cSJens Wiklander sym_idx = ELF32_R_SYM(rel->r_info); 364447354c6SJens Wiklander if (sym_idx >= num_syms) 365e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, 366447354c6SJens Wiklander "Symbol index out of range"); 3677509ff7cSJens Wiklander if (sym_tab[sym_idx].st_shndx == SHN_UNDEF) { 3687509ff7cSJens Wiklander /* Symbol is external */ 3697509ff7cSJens Wiklander e32_process_dyn_rel(sym_tab, num_syms, str_tab, 3707509ff7cSJens Wiklander str_tab_size, rel, where); 3717509ff7cSJens Wiklander } else { 3727509ff7cSJens Wiklander *where += elf->load_addr + 3737509ff7cSJens Wiklander sym_tab[sym_idx].st_value; 3747509ff7cSJens Wiklander } 3757509ff7cSJens Wiklander break; 3767509ff7cSJens Wiklander case R_ARM_REL32: 3777509ff7cSJens Wiklander sym_idx = ELF32_R_SYM(rel->r_info); 378447354c6SJens Wiklander if (sym_idx >= num_syms) 379e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, 380447354c6SJens Wiklander "Symbol index out of range"); 3817509ff7cSJens Wiklander *where += sym_tab[sym_idx].st_value - rel->r_offset; 3827509ff7cSJens Wiklander break; 3837509ff7cSJens Wiklander case R_ARM_RELATIVE: 3847509ff7cSJens Wiklander *where += elf->load_addr; 3857509ff7cSJens Wiklander break; 3867509ff7cSJens Wiklander case R_ARM_GLOB_DAT: 3877509ff7cSJens Wiklander case R_ARM_JUMP_SLOT: 3886897ad0fSJens Wiklander if (!sym_tab) 3896897ad0fSJens Wiklander err(TEE_ERROR_BAD_FORMAT, 3906897ad0fSJens Wiklander "Missing symbol table"); 3917509ff7cSJens Wiklander e32_process_dyn_rel(sym_tab, num_syms, str_tab, 3927509ff7cSJens Wiklander str_tab_size, rel, where); 3937509ff7cSJens Wiklander break; 394c88ba125SJerome Forissier case R_ARM_TLS_DTPMOD32: 3956897ad0fSJens Wiklander if (!sym_tab) 3966897ad0fSJens Wiklander err(TEE_ERROR_BAD_FORMAT, 3976897ad0fSJens Wiklander "Missing symbol table"); 398c88ba125SJerome Forissier mod = elf; 399c88ba125SJerome Forissier e32_tls_get_module(sym_tab, num_syms, str_tab, 400c88ba125SJerome Forissier str_tab_size, rel, &mod); 401c88ba125SJerome Forissier *where = mod->tls_mod_id; 402c88ba125SJerome Forissier break; 403c88ba125SJerome Forissier case R_ARM_TLS_DTPOFF32: 4046897ad0fSJens Wiklander if (!sym_tab) 4056897ad0fSJens Wiklander err(TEE_ERROR_BAD_FORMAT, 4066897ad0fSJens Wiklander "Missing symbol table"); 407c88ba125SJerome Forissier e32_tls_resolve(sym_tab, num_syms, str_tab, 408c88ba125SJerome Forissier str_tab_size, rel, &val); 409c88ba125SJerome Forissier *where = val; 410c88ba125SJerome Forissier break; 4117509ff7cSJens Wiklander default: 4127509ff7cSJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Unknown relocation type %d", 4137509ff7cSJens Wiklander ELF32_R_TYPE(rel->r_info)); 4147509ff7cSJens Wiklander } 4157509ff7cSJens Wiklander } 4167509ff7cSJens Wiklander } 4177509ff7cSJens Wiklander 4187509ff7cSJens Wiklander #ifdef ARM64 419fe684948SJerome Forissier static void e64_get_sym_name(const Elf64_Sym *sym_tab, size_t num_syms, 4207509ff7cSJens Wiklander const char *str_tab, size_t str_tab_size, 421*c44d734bSJerome Forissier Elf64_Rela *rela, const char **name, 422*c44d734bSJerome Forissier bool *weak_undef) 4237509ff7cSJens Wiklander { 4247509ff7cSJens Wiklander size_t sym_idx = 0; 4257509ff7cSJens Wiklander size_t name_idx = 0; 4267509ff7cSJens Wiklander 4277509ff7cSJens Wiklander sym_idx = ELF64_R_SYM(rela->r_info); 428447354c6SJens Wiklander if (sym_idx >= num_syms) 429e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Symbol index out of range"); 43055e64090SJens Wiklander sym_idx = confine_array_index(sym_idx, num_syms); 4317509ff7cSJens Wiklander 4327509ff7cSJens Wiklander name_idx = sym_tab[sym_idx].st_name; 433447354c6SJens Wiklander if (name_idx >= str_tab_size) 434e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Name index out of range"); 435fe684948SJerome Forissier *name = str_tab + name_idx; 436*c44d734bSJerome Forissier 437*c44d734bSJerome Forissier if (sym_tab[sym_idx].st_shndx == SHN_UNDEF && 438*c44d734bSJerome Forissier ELF64_ST_BIND(sym_tab[sym_idx].st_info) == STB_WEAK) 439*c44d734bSJerome Forissier *weak_undef = true; 440*c44d734bSJerome Forissier else 441*c44d734bSJerome Forissier *weak_undef = false; 442fe684948SJerome Forissier } 4437509ff7cSJens Wiklander 444fe684948SJerome Forissier static void e64_process_dyn_rela(const Elf64_Sym *sym_tab, size_t num_syms, 445fe684948SJerome Forissier const char *str_tab, size_t str_tab_size, 446fe684948SJerome Forissier Elf64_Rela *rela, Elf64_Addr *where) 447fe684948SJerome Forissier { 448fe684948SJerome Forissier const char *name = NULL; 449fe684948SJerome Forissier uintptr_t val = 0; 450*c44d734bSJerome Forissier bool weak_undef = false; 451fe684948SJerome Forissier 452*c44d734bSJerome Forissier e64_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rela, &name, 453*c44d734bSJerome Forissier &weak_undef); 454*c44d734bSJerome Forissier resolve_sym(name, &val, NULL, !weak_undef); 4557509ff7cSJens Wiklander *where = val; 4567509ff7cSJens Wiklander } 4577509ff7cSJens Wiklander 4587bc927faSJerome Forissier static void e64_process_tls_tprel_rela(const Elf64_Sym *sym_tab, 4597bc927faSJerome Forissier size_t num_syms, const char *str_tab, 4607bc927faSJerome Forissier size_t str_tab_size, Elf64_Rela *rela, 4617bc927faSJerome Forissier Elf64_Addr *where, struct ta_elf *elf) 462fe684948SJerome Forissier { 463fe684948SJerome Forissier struct ta_elf *mod = NULL; 464*c44d734bSJerome Forissier bool weak_undef = false; 465fe684948SJerome Forissier const char *name = NULL; 4667bc927faSJerome Forissier size_t sym_idx = 0; 467fe684948SJerome Forissier vaddr_t symval = 0; 468fe684948SJerome Forissier 4697bc927faSJerome Forissier sym_idx = ELF64_R_SYM(rela->r_info); 4707bc927faSJerome Forissier if (sym_idx) { 4717bc927faSJerome Forissier e64_get_sym_name(sym_tab, num_syms, str_tab, str_tab_size, rela, 472*c44d734bSJerome Forissier &name, &weak_undef); 473*c44d734bSJerome Forissier resolve_sym(name, &symval, &mod, !weak_undef); 4747bc927faSJerome Forissier } else { 4757bc927faSJerome Forissier mod = elf; 4767bc927faSJerome Forissier } 477fe684948SJerome Forissier *where = symval + mod->tls_tcb_offs + rela->r_addend; 478fe684948SJerome Forissier } 479fe684948SJerome Forissier 4807bc927faSJerome Forissier struct tlsdesc { 4817bc927faSJerome Forissier long (*resolver)(struct tlsdesc *td); 4827bc927faSJerome Forissier long value; 4837bc927faSJerome Forissier }; 4847bc927faSJerome Forissier 4857bc927faSJerome Forissier /* Helper function written in assembly due to the calling convention */ 4867bc927faSJerome Forissier long tlsdesc_resolve(struct tlsdesc *td); 4877bc927faSJerome Forissier 4887bc927faSJerome Forissier static void e64_process_tlsdesc_rela(const Elf64_Sym *sym_tab, size_t num_syms, 4897bc927faSJerome Forissier const char *str_tab, size_t str_tab_size, 4907bc927faSJerome Forissier Elf64_Rela *rela, Elf64_Addr *where, 4917bc927faSJerome Forissier struct ta_elf *elf) 4927bc927faSJerome Forissier { 4937bc927faSJerome Forissier /* 4947bc927faSJerome Forissier * @where points to a pair of 64-bit words in the GOT or PLT which is 4957bc927faSJerome Forissier * mapped to a struct tlsdesc: 4967bc927faSJerome Forissier * 4977bc927faSJerome Forissier * - resolver() must return the offset of the thread-local variable 4987bc927faSJerome Forissier * relative to TPIDR_EL0. 4997bc927faSJerome Forissier * - value is implementation-dependent. The TLS_TPREL handling code is 5007bc927faSJerome Forissier * re-used to get the desired offset so that tlsdesc_resolve() just 5017bc927faSJerome Forissier * needs to return this value. 5027bc927faSJerome Forissier * 5037bc927faSJerome Forissier * Both the TA and ldelf are AArch64 so it is OK to point to a function 5047bc927faSJerome Forissier * in ldelf. 5057bc927faSJerome Forissier */ 5067bc927faSJerome Forissier *where = (Elf64_Addr)tlsdesc_resolve; 5077bc927faSJerome Forissier e64_process_tls_tprel_rela(sym_tab, num_syms, str_tab, str_tab_size, 5087bc927faSJerome Forissier rela, where + 1, elf); 5097bc927faSJerome Forissier } 5107bc927faSJerome Forissier 5117509ff7cSJens Wiklander static void e64_relocate(struct ta_elf *elf, unsigned int rel_sidx) 5127509ff7cSJens Wiklander { 5137509ff7cSJens Wiklander Elf64_Shdr *shdr = elf->shdr; 5147509ff7cSJens Wiklander Elf64_Rela *rela = NULL; 5157509ff7cSJens Wiklander Elf64_Rela *rela_end = NULL; 5167509ff7cSJens Wiklander size_t sym_tab_idx = 0; 5177509ff7cSJens Wiklander Elf64_Sym *sym_tab = NULL; 5187509ff7cSJens Wiklander size_t num_syms = 0; 5197509ff7cSJens Wiklander size_t sh_end = 0; 5207509ff7cSJens Wiklander const char *str_tab = NULL; 5217509ff7cSJens Wiklander size_t str_tab_size = 0; 5227509ff7cSJens Wiklander 5237509ff7cSJens Wiklander assert(shdr[rel_sidx].sh_type == SHT_RELA); 5247509ff7cSJens Wiklander 5257509ff7cSJens Wiklander assert(shdr[rel_sidx].sh_entsize == sizeof(Elf64_Rela)); 5267509ff7cSJens Wiklander 5277509ff7cSJens Wiklander sym_tab_idx = shdr[rel_sidx].sh_link; 5287509ff7cSJens Wiklander if (sym_tab_idx) { 5297509ff7cSJens Wiklander size_t str_tab_idx = 0; 5307509ff7cSJens Wiklander 531447354c6SJens Wiklander if (sym_tab_idx >= elf->e_shnum) 532dcf64f87SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "SYMTAB index out of range"); 53355e64090SJens Wiklander sym_tab_idx = confine_array_index(sym_tab_idx, elf->e_shnum); 5347509ff7cSJens Wiklander 5357509ff7cSJens Wiklander assert(shdr[sym_tab_idx].sh_entsize == sizeof(Elf64_Sym)); 5367509ff7cSJens Wiklander 5377509ff7cSJens Wiklander /* Check the address is inside TA memory */ 5387509ff7cSJens Wiklander if (ADD_OVERFLOW(shdr[sym_tab_idx].sh_addr, 5397509ff7cSJens Wiklander shdr[sym_tab_idx].sh_size, &sh_end)) 540e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Overflow"); 541447354c6SJens Wiklander if (sh_end >= (elf->max_addr - elf->load_addr)) 542dcf64f87SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "SYMTAB out of range"); 5437509ff7cSJens Wiklander 5447509ff7cSJens Wiklander sym_tab = (Elf64_Sym *)(elf->load_addr + 5457509ff7cSJens Wiklander shdr[sym_tab_idx].sh_addr); 5467509ff7cSJens Wiklander 5477509ff7cSJens Wiklander num_syms = shdr[sym_tab_idx].sh_size / sizeof(Elf64_Sym); 5487509ff7cSJens Wiklander 5497509ff7cSJens Wiklander str_tab_idx = shdr[sym_tab_idx].sh_link; 5507509ff7cSJens Wiklander if (str_tab_idx) { 55155e64090SJens Wiklander if (str_tab_idx >= elf->e_shnum) 552e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, 553dcf64f87SJens Wiklander "STRTAB index out of range"); 55455e64090SJens Wiklander str_tab_idx = confine_array_index(str_tab_idx, 55555e64090SJens Wiklander elf->e_shnum); 55655e64090SJens Wiklander 5577509ff7cSJens Wiklander /* Check the address is inside ELF memory */ 5587509ff7cSJens Wiklander if (ADD_OVERFLOW(shdr[str_tab_idx].sh_addr, 5597509ff7cSJens Wiklander shdr[str_tab_idx].sh_size, &sh_end)) 560e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Overflow"); 561447354c6SJens Wiklander if (sh_end >= (elf->max_addr - elf->load_addr)) 562e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, 563dcf64f87SJens Wiklander "STRTAB out of range"); 5647509ff7cSJens Wiklander 5657509ff7cSJens Wiklander str_tab = (const char *)(elf->load_addr + 5667509ff7cSJens Wiklander shdr[str_tab_idx].sh_addr); 5677509ff7cSJens Wiklander str_tab_size = shdr[str_tab_idx].sh_size; 5687509ff7cSJens Wiklander } 5697509ff7cSJens Wiklander } 5707509ff7cSJens Wiklander 5717509ff7cSJens Wiklander /* Check the address is inside TA memory */ 572447354c6SJens Wiklander if (ADD_OVERFLOW(shdr[rel_sidx].sh_addr, 573447354c6SJens Wiklander shdr[rel_sidx].sh_size, &sh_end)) 574e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Overflow"); 575447354c6SJens Wiklander if (sh_end >= (elf->max_addr - elf->load_addr)) 576dcf64f87SJens Wiklander err(TEE_ERROR_BAD_FORMAT, ".rel.*/REL out of range"); 5777509ff7cSJens Wiklander rela = (Elf64_Rela *)(elf->load_addr + shdr[rel_sidx].sh_addr); 5787509ff7cSJens Wiklander 5797509ff7cSJens Wiklander rela_end = rela + shdr[rel_sidx].sh_size / sizeof(Elf64_Rela); 5807509ff7cSJens Wiklander for (; rela < rela_end; rela++) { 5817509ff7cSJens Wiklander Elf64_Addr *where = NULL; 5827509ff7cSJens Wiklander size_t sym_idx = 0; 5837509ff7cSJens Wiklander 5847509ff7cSJens Wiklander /* Check the address is inside TA memory */ 585447354c6SJens Wiklander if (rela->r_offset >= (elf->max_addr - elf->load_addr)) 586e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, 587447354c6SJens Wiklander "Relocation offset out of range"); 5887509ff7cSJens Wiklander 5897509ff7cSJens Wiklander where = (Elf64_Addr *)(elf->load_addr + rela->r_offset); 5907509ff7cSJens Wiklander 5917509ff7cSJens Wiklander switch (ELF64_R_TYPE(rela->r_info)) { 5927a4dc765SEtienne Carriere case R_AARCH64_NONE: 5937a4dc765SEtienne Carriere /* 5947a4dc765SEtienne Carriere * One would expect linker prevents such useless entry 5957a4dc765SEtienne Carriere * in the relocation table. We still handle this type 5967a4dc765SEtienne Carriere * here in case such entries exist. 5977a4dc765SEtienne Carriere */ 5987a4dc765SEtienne Carriere break; 5997509ff7cSJens Wiklander case R_AARCH64_ABS64: 6007509ff7cSJens Wiklander sym_idx = ELF64_R_SYM(rela->r_info); 601447354c6SJens Wiklander if (sym_idx >= num_syms) 602e97bbbb2SJens Wiklander err(TEE_ERROR_BAD_FORMAT, 603447354c6SJens Wiklander "Symbol index out of range"); 60455e64090SJens Wiklander sym_idx = confine_array_index(sym_idx, num_syms); 6057509ff7cSJens Wiklander if (sym_tab[sym_idx].st_shndx == SHN_UNDEF) { 6067509ff7cSJens Wiklander /* Symbol is external */ 6077509ff7cSJens Wiklander e64_process_dyn_rela(sym_tab, num_syms, str_tab, 6087509ff7cSJens Wiklander str_tab_size, rela, where); 6097509ff7cSJens Wiklander } else { 6107509ff7cSJens Wiklander *where = rela->r_addend + elf->load_addr + 6117509ff7cSJens Wiklander sym_tab[sym_idx].st_value; 6127509ff7cSJens Wiklander } 6137509ff7cSJens Wiklander break; 6147509ff7cSJens Wiklander case R_AARCH64_RELATIVE: 6157509ff7cSJens Wiklander *where = rela->r_addend + elf->load_addr; 6167509ff7cSJens Wiklander break; 6177509ff7cSJens Wiklander case R_AARCH64_GLOB_DAT: 6187509ff7cSJens Wiklander case R_AARCH64_JUMP_SLOT: 6197509ff7cSJens Wiklander e64_process_dyn_rela(sym_tab, num_syms, str_tab, 6207509ff7cSJens Wiklander str_tab_size, rela, where); 6217509ff7cSJens Wiklander break; 622fe684948SJerome Forissier case R_AARCH64_TLS_TPREL: 6237bc927faSJerome Forissier e64_process_tls_tprel_rela(sym_tab, num_syms, str_tab, 6247bc927faSJerome Forissier str_tab_size, rela, where, 6257bc927faSJerome Forissier elf); 6267bc927faSJerome Forissier break; 6277bc927faSJerome Forissier case R_AARCH64_TLSDESC: 6287bc927faSJerome Forissier e64_process_tlsdesc_rela(sym_tab, num_syms, str_tab, 6297bc927faSJerome Forissier str_tab_size, rela, where, 6307bc927faSJerome Forissier elf); 631fe684948SJerome Forissier break; 6327509ff7cSJens Wiklander default: 6337509ff7cSJens Wiklander err(TEE_ERROR_BAD_FORMAT, "Unknown relocation type %zd", 6347509ff7cSJens Wiklander ELF64_R_TYPE(rela->r_info)); 6357509ff7cSJens Wiklander } 6367509ff7cSJens Wiklander } 6377509ff7cSJens Wiklander } 6387509ff7cSJens Wiklander #else /*ARM64*/ 6395548a710SJerome Forissier static void __noreturn e64_relocate(struct ta_elf *elf __unused, 6407509ff7cSJens Wiklander unsigned int rel_sidx __unused) 6417509ff7cSJens Wiklander { 6427509ff7cSJens Wiklander err(TEE_ERROR_NOT_SUPPORTED, "arm64 not supported"); 6437509ff7cSJens Wiklander } 6447509ff7cSJens Wiklander #endif /*ARM64*/ 6457509ff7cSJens Wiklander 6467509ff7cSJens Wiklander void ta_elf_relocate(struct ta_elf *elf) 6477509ff7cSJens Wiklander { 6487509ff7cSJens Wiklander size_t n = 0; 6497509ff7cSJens Wiklander 6507509ff7cSJens Wiklander if (elf->is_32bit) { 6517509ff7cSJens Wiklander Elf32_Shdr *shdr = elf->shdr; 6527509ff7cSJens Wiklander 6537509ff7cSJens Wiklander for (n = 0; n < elf->e_shnum; n++) 6547509ff7cSJens Wiklander if (shdr[n].sh_type == SHT_REL) 6557509ff7cSJens Wiklander e32_relocate(elf, n); 6567509ff7cSJens Wiklander } else { 6577509ff7cSJens Wiklander Elf64_Shdr *shdr = elf->shdr; 6587509ff7cSJens Wiklander 6597509ff7cSJens Wiklander for (n = 0; n < elf->e_shnum; n++) 6607509ff7cSJens Wiklander if (shdr[n].sh_type == SHT_RELA) 6617509ff7cSJens Wiklander e64_relocate(elf, n); 6627509ff7cSJens Wiklander 6637509ff7cSJens Wiklander } 6647509ff7cSJens Wiklander } 665