mirror of
https://github.com/corda/corda.git
synced 2025-01-09 14:33:30 +00:00
9441de4c38
This release is used in conjunction with the linux-sgx-driver Intial release: https://github.com/01org/linux-sgx-driver commit-id: 0e865ce5e6b297a787bcdc12d98bada8174be6d7 Intel-id: 33399 Signed-off-by: Angie Chinchilla <angie.v.chinchilla@intel.com>
420 lines
13 KiB
C
420 lines
13 KiB
C
/*
|
|
* 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: */
|