123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- /*
- * Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- /*
- * This file is part of trusted loader for tRTS.
- */
- #include "elf_parser.h"
- #include "rts.h"
- #include "util.h"
- #include "elf_util.h"
- #include "global_data.h"
- static int elf_tls_aligned_virtual_size(const void *enclave_base,
- size_t *aligned_virtual_size);
- static ElfW(Phdr)* get_phdr(const ElfW(Ehdr)* ehdr)
- {
- if (ehdr == NULL)
- return NULL; /* Invalid image. */
- /* Check the ElfW Magic number. */
- if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
- (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
- (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
- (ehdr->e_ident[EI_MAG3] != ELFMAG3))
- return NULL;
- /* Enclave image should be a shared object file. */
- if (ehdr->e_type != ET_DYN)
- return NULL;
- return GET_PTR(ElfW(Phdr), ehdr, ehdr->e_phoff);
- }
- static ElfW(Sym)* get_sym(ElfW(Sym)* symtab, size_t idx)
- {
- if(STB_WEAK == ELFW(ST_BIND)(symtab[idx].st_info)
- && 0 == symtab[idx].st_value)
- {
- return NULL;
- }
- return &symtab[idx];
- }
- #ifdef __x86_64__
- /* Relocation for x64 (with addend) */
- static int do_relocs(const ElfW(Addr) enclave_base,
- ElfW(Addr) rela_offset,
- ElfW(Addr) sym_offset,
- size_t nr_relocs)
- {
- ElfW(Rela)* rela = GET_PTR(ElfW(Rela), enclave_base, rela_offset);
- ElfW(Sym)* symtab = GET_PTR(ElfW(Sym), enclave_base, sym_offset);
- ElfW(Sym)* sym;
- size_t i;
- size_t aligned_virtual_size = 0;
- for (i = 0; i < nr_relocs; ++i, ++rela)
- {
- ElfW(Addr)* reloc_addr = GET_PTR(ElfW(Addr), enclave_base, rela->r_offset);
- switch (ELF64_R_TYPE(rela->r_info))
- {
- case R_X86_64_RELATIVE:
- *reloc_addr = enclave_base + (uintptr_t)rela->r_addend;
- break;
- case R_X86_64_GLOB_DAT:
- case R_X86_64_JUMP_SLOT:
- case R_X86_64_64:
- sym = get_sym(symtab, ELF64_R_SYM(rela->r_info));
- if(!sym)
- break;
- *reloc_addr = enclave_base + sym->st_value + (uintptr_t)rela->r_addend;
- break;
- case R_X86_64_DTPMOD64:
- *reloc_addr = 1;
- break;
-
- case R_X86_64_DTPOFF64:
- sym = get_sym(symtab, ELF64_R_SYM(rela->r_info));
- if(!sym)
- break;
- *reloc_addr = sym->st_value + (uintptr_t)rela->r_addend;
- break;
- case R_X86_64_TPOFF64:
- sym = get_sym(symtab, ELF64_R_SYM(rela->r_info));
- if(!sym)
- break;
- if ((0 == elf_tls_aligned_virtual_size((void *)enclave_base, &aligned_virtual_size)) && (aligned_virtual_size))
- {
- *reloc_addr = sym->st_value + (uintptr_t)rela->r_addend - aligned_virtual_size;
- break;
- }
- else
- return -1;
- case R_X86_64_NONE:
- break;
- default: /* unsupported relocs */
- return -1;
- }
- }
- return 0;
- }
- #elif defined(__i386__)
- /* Relocation for x86 (without addend) */
- static int do_relocs(const ElfW(Addr) enclave_base,
- ElfW(Addr) rel_offset,
- ElfW(Addr) sym_offset,
- size_t nr_relocs)
- {
- ElfW(Rel)* rel = GET_PTR(ElfW(Rel), enclave_base, rel_offset);
- ElfW(Sym)* symtab = GET_PTR(ElfW(Sym), enclave_base, sym_offset);
- ElfW(Sym)* sym = NULL;
- size_t i;
- size_t aligned_virtual_size = 0;
- for (i = 0; i < nr_relocs; ++i, ++rel)
- {
- ElfW(Addr)* reloc_addr = GET_PTR(ElfW(Addr), enclave_base, rel->r_offset);
- if(R_386_RELATIVE == ELF32_R_TYPE(rel->r_info))
- {
- *reloc_addr += enclave_base; /* B+A */
- continue;
- }
- sym = get_sym(symtab, ELF32_R_SYM(rel->r_info));
- if(!sym) /* when the weak symbol is not implemented, sym is NULL */
- continue;
- switch (ELF32_R_TYPE(rel->r_info))
- {
- case R_386_GLOB_DAT:
- case R_386_JMP_SLOT: /* S */
- *reloc_addr = enclave_base + sym->st_value;
- break;
- case R_386_32: /* S+A */
- *reloc_addr += enclave_base + sym->st_value;
- break;
- case R_386_PC32: /* S+A-P */
- *reloc_addr += (enclave_base + sym->st_value - (ElfW(Addr))reloc_addr);
- break;
- case R_386_NONE:
- break;
- case R_386_TLS_DTPMOD32:
- *reloc_addr = 1;
- break;
-
- case R_386_TLS_DTPOFF32:
- *reloc_addr = sym->st_value;
- break;
- case R_386_TLS_TPOFF:
- if ((0 == elf_tls_aligned_virtual_size((void *)enclave_base, &aligned_virtual_size)) && (aligned_virtual_size))
- {
- *reloc_addr += sym->st_value - aligned_virtual_size;
- break;
- }
- else
- return -1;
- case R_386_TLS_TPOFF32:
- if ((0 == elf_tls_aligned_virtual_size((void *)enclave_base, &aligned_virtual_size)) && (aligned_virtual_size))
- {
- *reloc_addr += aligned_virtual_size - sym->st_value;
- break;
- }
- else
- return -1;
- default: /* unsupported relocs */
- return -1;
- }
- }
- return 0;
- }
- #endif
- #define DO_REL(base_addr, rel_offset, sym_offset, total_sz, rel_entry_sz) \
- do { \
- if (rel_offset) \
- { \
- size_t n; \
- if (rel_entry_sz == 0) \
- return -1; \
- n = total_sz/rel_entry_sz; \
- if (do_relocs((ElfW(Addr))enclave_base, rel_offset, sym_offset, n)) \
- return -1; \
- } \
- } while (0)
- /* By default all symbol is linked as global symbol by link editor. When call global symbol,
- * we first call .plt entry. It should have problems if the call goloal symbol when relocation
- * is not done.
- * Declare relocate_enclave as .hidden is to make it local symbol.
- * Since this function is called before relocation is done, we must make
- * it local symbol, so the code is like "fce3: e8 98 12 00 00 call 10f80 <relocate_enclave>"
- * 0x9812=0x10f80-0xfce8
- */
- __attribute__ ((visibility ("hidden")))
- int relocate_enclave(void* enclave_base)
- {
- ElfW(Half) phnum = 0;
- ElfW(Ehdr) *ehdr = (ElfW(Ehdr)*)enclave_base;
- ElfW(Phdr) *phdr = get_phdr(ehdr);
- if (phdr == NULL)
- return -1; /* Invalid image. */
- for (; phnum < ehdr->e_phnum; phnum++, phdr++)
- {
- /* Search for dynamic segment */
- if (phdr->p_type == PT_DYNAMIC)
- {
- size_t count;
- size_t n_dyn = phdr->p_filesz/sizeof(ElfW(Dyn));
- ElfW(Dyn) *dyn = GET_PTR(ElfW(Dyn), ehdr, phdr->p_paddr);
- ElfW(Addr) sym_offset = 0;
- ElfW(Addr) rel_offset = 0;
- ElfW(Addr) plt_offset = 0;
- size_t rel_total_sz = 0;
- size_t rel_entry_sz = 0;
- size_t plt_total_sz = 0;
- for (count = 0; count < n_dyn; count++, dyn++)
- {
- if (dyn->d_tag == DT_NULL) /* End */
- break;
- switch (dyn->d_tag)
- {
- case DT_SYMTAB: /* symbol table */
- sym_offset = dyn->d_un.d_ptr;
- break;
- case RTS_DT_REL:/* Rel (x86) or Rela (x64) relocs */
- rel_offset = dyn->d_un.d_ptr;
- break;
- case RTS_DT_RELSZ:
- rel_total_sz = dyn->d_un.d_val;
- break;
- case RTS_DT_RELENT:
- rel_entry_sz = dyn->d_un.d_val;
- break;
- case DT_JMPREL: /* PLT relocs */
- plt_offset = dyn->d_un.d_ptr;
- break;
- case DT_PLTRELSZ:
- plt_total_sz = dyn->d_un.d_val;
- break;
- }
- }
- DO_REL(enclave_base, rel_offset, sym_offset, rel_total_sz, rel_entry_sz);
- DO_REL(enclave_base, plt_offset, sym_offset, plt_total_sz, rel_entry_sz);
- }
- }
- return 0;
- }
- int elf_tls_info(const void* enclave_base,
- uintptr_t *tls_addr, size_t *tdata_size)
- {
- ElfW(Half) phnum = 0;
- const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr)*)enclave_base;
- ElfW(Phdr) *phdr = get_phdr(ehdr);
- if (!tls_addr || !tdata_size)
- return -1;
- if (phdr == NULL)
- return -1; /* Invalid image. */
- /* Search for TLS segment */
- *tls_addr = 0;
- *tdata_size = 0;
- for (; phnum < ehdr->e_phnum; phnum++, phdr++)
- {
- if (phdr->p_type == PT_TLS)
- {
- /* tls_addr here is got from the program header, the address
- * need to be added by the enclave base.
- */
- *tls_addr = (size_t)enclave_base + phdr->p_vaddr;
- *tdata_size = phdr->p_filesz;
- break;
- }
- }
- return 0;
- }
- static int elf_tls_aligned_virtual_size(const void *enclave_base,
- size_t *aligned_virtual_size)
- {
- ElfW(Half) phnum = 0;
- const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr)*)enclave_base;
- ElfW(Phdr) *phdr = get_phdr(ehdr);
- size_t virtual_size =0, align = 0;
- if (phdr == NULL)
- return -1;
- if (!aligned_virtual_size)
- return -1;
- *aligned_virtual_size = 0;
- for (; phnum < ehdr->e_phnum; phnum++, phdr++)
- {
- if (phdr->p_type == PT_TLS)
- {
- virtual_size = phdr->p_memsz;
- align = phdr->p_align;
- /* p_align == 0 or p_align == 1 means no alignment is required */
- if (align == 0 || align == 1)
- *aligned_virtual_size = virtual_size;
- else
- *aligned_virtual_size = (virtual_size + align - 1) & (~(align - 1));
- break;
- }
- }
- return 0;
- }
- int elf_get_init_array(const void* enclave_base,
- uintptr_t *init_array_addr, size_t *init_array_size)
- {
- ElfW(Half) phnum = 0;
- const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr)*)enclave_base;
- ElfW(Phdr) *phdr = get_phdr(ehdr);
- if (!init_array_addr || !init_array_size)
- return -1;
- if (phdr == NULL)
- return -1; /* Invalid image. */
- *init_array_addr = 0;
- *init_array_size = 0;
- /* Search for Dynamic segment */
- for (; phnum < ehdr->e_phnum; phnum++, phdr++)
- {
- if (phdr->p_type == PT_DYNAMIC)
- {
- size_t count;
- size_t n_dyn = phdr->p_filesz/sizeof(ElfW(Dyn));
- ElfW(Dyn) *dyn = GET_PTR(ElfW(Dyn), ehdr, phdr->p_paddr);
-
- for (count = 0; count < n_dyn; count++, dyn++)
- {
- switch (dyn->d_tag)
- {
- case DT_INIT_ARRAY:
- *init_array_addr = dyn->d_un.d_ptr;
- break;
- case DT_INIT_ARRAYSZ:
- *init_array_size = dyn->d_un.d_val;
- break;
- }
- }
- }
- }
- return 0;
- }
- /* vim: set ts=4 sw=4 et cin: */
|