elf_parser.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /*
  2. * Copyright (C) 2011-2017 Intel Corporation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Intel Corporation nor the names of its
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. /*
  32. * This file is part of trusted loader for tRTS.
  33. */
  34. #include "elf_parser.h"
  35. #include "rts.h"
  36. #include "util.h"
  37. #include "elf_util.h"
  38. #include "global_data.h"
  39. static int elf_tls_aligned_virtual_size(const void *enclave_base,
  40. size_t *aligned_virtual_size);
  41. static ElfW(Phdr)* get_phdr(const ElfW(Ehdr)* ehdr)
  42. {
  43. if (ehdr == NULL)
  44. return NULL; /* Invalid image. */
  45. /* Check the ElfW Magic number. */
  46. if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
  47. (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
  48. (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
  49. (ehdr->e_ident[EI_MAG3] != ELFMAG3))
  50. return NULL;
  51. /* Enclave image should be a shared object file. */
  52. if (ehdr->e_type != ET_DYN)
  53. return NULL;
  54. return GET_PTR(ElfW(Phdr), ehdr, ehdr->e_phoff);
  55. }
  56. static ElfW(Sym)* get_sym(ElfW(Sym)* symtab, size_t idx)
  57. {
  58. if(STB_WEAK == ELFW(ST_BIND)(symtab[idx].st_info)
  59. && 0 == symtab[idx].st_value)
  60. {
  61. return NULL;
  62. }
  63. return &symtab[idx];
  64. }
  65. #ifdef __x86_64__
  66. /* Relocation for x64 (with addend) */
  67. static int do_relocs(const ElfW(Addr) enclave_base,
  68. ElfW(Addr) rela_offset,
  69. ElfW(Addr) sym_offset,
  70. size_t nr_relocs)
  71. {
  72. ElfW(Rela)* rela = GET_PTR(ElfW(Rela), enclave_base, rela_offset);
  73. ElfW(Sym)* symtab = GET_PTR(ElfW(Sym), enclave_base, sym_offset);
  74. ElfW(Sym)* sym;
  75. size_t i;
  76. size_t aligned_virtual_size = 0;
  77. for (i = 0; i < nr_relocs; ++i, ++rela)
  78. {
  79. ElfW(Addr)* reloc_addr = GET_PTR(ElfW(Addr), enclave_base, rela->r_offset);
  80. switch (ELF64_R_TYPE(rela->r_info))
  81. {
  82. case R_X86_64_RELATIVE:
  83. *reloc_addr = enclave_base + (uintptr_t)rela->r_addend;
  84. break;
  85. case R_X86_64_GLOB_DAT:
  86. case R_X86_64_JUMP_SLOT:
  87. case R_X86_64_64:
  88. sym = get_sym(symtab, ELF64_R_SYM(rela->r_info));
  89. if(!sym)
  90. break;
  91. *reloc_addr = enclave_base + sym->st_value + (uintptr_t)rela->r_addend;
  92. break;
  93. case R_X86_64_DTPMOD64:
  94. *reloc_addr = 1;
  95. break;
  96. case R_X86_64_DTPOFF64:
  97. sym = get_sym(symtab, ELF64_R_SYM(rela->r_info));
  98. if(!sym)
  99. break;
  100. *reloc_addr = sym->st_value + (uintptr_t)rela->r_addend;
  101. break;
  102. case R_X86_64_TPOFF64:
  103. sym = get_sym(symtab, ELF64_R_SYM(rela->r_info));
  104. if(!sym)
  105. break;
  106. if ((0 == elf_tls_aligned_virtual_size((void *)enclave_base, &aligned_virtual_size)) && (aligned_virtual_size))
  107. {
  108. *reloc_addr = sym->st_value + (uintptr_t)rela->r_addend - aligned_virtual_size;
  109. break;
  110. }
  111. else
  112. return -1;
  113. case R_X86_64_NONE:
  114. break;
  115. default: /* unsupported relocs */
  116. return -1;
  117. }
  118. }
  119. return 0;
  120. }
  121. #elif defined(__i386__)
  122. /* Relocation for x86 (without addend) */
  123. static int do_relocs(const ElfW(Addr) enclave_base,
  124. ElfW(Addr) rel_offset,
  125. ElfW(Addr) sym_offset,
  126. size_t nr_relocs)
  127. {
  128. ElfW(Rel)* rel = GET_PTR(ElfW(Rel), enclave_base, rel_offset);
  129. ElfW(Sym)* symtab = GET_PTR(ElfW(Sym), enclave_base, sym_offset);
  130. ElfW(Sym)* sym = NULL;
  131. size_t i;
  132. size_t aligned_virtual_size = 0;
  133. for (i = 0; i < nr_relocs; ++i, ++rel)
  134. {
  135. ElfW(Addr)* reloc_addr = GET_PTR(ElfW(Addr), enclave_base, rel->r_offset);
  136. if(R_386_RELATIVE == ELF32_R_TYPE(rel->r_info))
  137. {
  138. *reloc_addr += enclave_base; /* B+A */
  139. continue;
  140. }
  141. sym = get_sym(symtab, ELF32_R_SYM(rel->r_info));
  142. if(!sym) /* when the weak symbol is not implemented, sym is NULL */
  143. continue;
  144. switch (ELF32_R_TYPE(rel->r_info))
  145. {
  146. case R_386_GLOB_DAT:
  147. case R_386_JMP_SLOT: /* S */
  148. *reloc_addr = enclave_base + sym->st_value;
  149. break;
  150. case R_386_32: /* S+A */
  151. *reloc_addr += enclave_base + sym->st_value;
  152. break;
  153. case R_386_PC32: /* S+A-P */
  154. *reloc_addr += (enclave_base + sym->st_value - (ElfW(Addr))reloc_addr);
  155. break;
  156. case R_386_NONE:
  157. break;
  158. case R_386_TLS_DTPMOD32:
  159. *reloc_addr = 1;
  160. break;
  161. case R_386_TLS_DTPOFF32:
  162. *reloc_addr = sym->st_value;
  163. break;
  164. case R_386_TLS_TPOFF:
  165. if ((0 == elf_tls_aligned_virtual_size((void *)enclave_base, &aligned_virtual_size)) && (aligned_virtual_size))
  166. {
  167. *reloc_addr += sym->st_value - aligned_virtual_size;
  168. break;
  169. }
  170. else
  171. return -1;
  172. case R_386_TLS_TPOFF32:
  173. if ((0 == elf_tls_aligned_virtual_size((void *)enclave_base, &aligned_virtual_size)) && (aligned_virtual_size))
  174. {
  175. *reloc_addr += aligned_virtual_size - sym->st_value;
  176. break;
  177. }
  178. else
  179. return -1;
  180. default: /* unsupported relocs */
  181. return -1;
  182. }
  183. }
  184. return 0;
  185. }
  186. #endif
  187. #define DO_REL(base_addr, rel_offset, sym_offset, total_sz, rel_entry_sz) \
  188. do { \
  189. if (rel_offset) \
  190. { \
  191. size_t n; \
  192. if (rel_entry_sz == 0) \
  193. return -1; \
  194. n = total_sz/rel_entry_sz; \
  195. if (do_relocs((ElfW(Addr))base_addr, rel_offset, sym_offset, n)) \
  196. return -1; \
  197. } \
  198. } while (0)
  199. /* By default all symbol is linked as global symbol by link editor. When call global symbol,
  200. * we first call .plt entry. It should have problems if the call goloal symbol when relocation
  201. * is not done.
  202. * Declare relocate_enclave as .hidden is to make it local symbol.
  203. * Since this function is called before relocation is done, we must make
  204. * it local symbol, so the code is like "fce3: e8 98 12 00 00 call 10f80 <relocate_enclave>"
  205. * 0x9812=0x10f80-0xfce8
  206. */
  207. __attribute__ ((visibility ("hidden")))
  208. int relocate_enclave(void* enclave_base)
  209. {
  210. ElfW(Half) phnum = 0;
  211. ElfW(Ehdr) *ehdr = (ElfW(Ehdr)*)enclave_base;
  212. ElfW(Phdr) *phdr = get_phdr(ehdr);
  213. if (phdr == NULL)
  214. return -1; /* Invalid image. */
  215. for (; phnum < ehdr->e_phnum; phnum++, phdr++)
  216. {
  217. /* Search for dynamic segment */
  218. if (phdr->p_type == PT_DYNAMIC)
  219. {
  220. size_t count;
  221. size_t n_dyn = phdr->p_filesz/sizeof(ElfW(Dyn));
  222. ElfW(Dyn) *dyn = GET_PTR(ElfW(Dyn), ehdr, phdr->p_paddr);
  223. ElfW(Addr) sym_offset = 0;
  224. ElfW(Addr) rel_offset = 0;
  225. ElfW(Addr) plt_offset = 0;
  226. size_t rel_total_sz = 0;
  227. size_t rel_entry_sz = 0;
  228. size_t plt_total_sz = 0;
  229. for (count = 0; count < n_dyn; count++, dyn++)
  230. {
  231. if (dyn->d_tag == DT_NULL) /* End */
  232. break;
  233. switch (dyn->d_tag)
  234. {
  235. case DT_SYMTAB: /* symbol table */
  236. sym_offset = dyn->d_un.d_ptr;
  237. break;
  238. case RTS_DT_REL:/* Rel (x86) or Rela (x64) relocs */
  239. rel_offset = dyn->d_un.d_ptr;
  240. break;
  241. case RTS_DT_RELSZ:
  242. rel_total_sz = dyn->d_un.d_val;
  243. break;
  244. case RTS_DT_RELENT:
  245. rel_entry_sz = dyn->d_un.d_val;
  246. break;
  247. case DT_JMPREL: /* PLT relocs */
  248. plt_offset = dyn->d_un.d_ptr;
  249. break;
  250. case DT_PLTRELSZ:
  251. plt_total_sz = dyn->d_un.d_val;
  252. break;
  253. }
  254. }
  255. DO_REL(enclave_base, rel_offset, sym_offset, rel_total_sz, rel_entry_sz);
  256. DO_REL(enclave_base, plt_offset, sym_offset, plt_total_sz, rel_entry_sz);
  257. }
  258. }
  259. return 0;
  260. }
  261. int elf_tls_info(const void* enclave_base,
  262. uintptr_t *tls_addr, size_t *tdata_size)
  263. {
  264. ElfW(Half) phnum = 0;
  265. const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr)*)enclave_base;
  266. ElfW(Phdr) *phdr = get_phdr(ehdr);
  267. if (!tls_addr || !tdata_size)
  268. return -1;
  269. if (phdr == NULL)
  270. return -1; /* Invalid image. */
  271. /* Search for TLS segment */
  272. *tls_addr = 0;
  273. *tdata_size = 0;
  274. for (; phnum < ehdr->e_phnum; phnum++, phdr++)
  275. {
  276. if (phdr->p_type == PT_TLS)
  277. {
  278. /* tls_addr here is got from the program header, the address
  279. * need to be added by the enclave base.
  280. */
  281. *tls_addr = (size_t)enclave_base + phdr->p_vaddr;
  282. *tdata_size = phdr->p_filesz;
  283. break;
  284. }
  285. }
  286. return 0;
  287. }
  288. static int elf_tls_aligned_virtual_size(const void *enclave_base,
  289. size_t *aligned_virtual_size)
  290. {
  291. ElfW(Half) phnum = 0;
  292. const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr)*)enclave_base;
  293. ElfW(Phdr) *phdr = get_phdr(ehdr);
  294. size_t virtual_size =0, align = 0;
  295. if (phdr == NULL)
  296. return -1;
  297. if (!aligned_virtual_size)
  298. return -1;
  299. *aligned_virtual_size = 0;
  300. for (; phnum < ehdr->e_phnum; phnum++, phdr++)
  301. {
  302. if (phdr->p_type == PT_TLS)
  303. {
  304. virtual_size = phdr->p_memsz;
  305. align = phdr->p_align;
  306. /* p_align == 0 or p_align == 1 means no alignment is required */
  307. if (align == 0 || align == 1)
  308. *aligned_virtual_size = virtual_size;
  309. else
  310. *aligned_virtual_size = (virtual_size + align - 1) & (~(align - 1));
  311. break;
  312. }
  313. }
  314. return 0;
  315. }
  316. int elf_get_init_array(const void* enclave_base,
  317. uintptr_t *init_array_addr, size_t *init_array_size)
  318. {
  319. ElfW(Half) phnum = 0;
  320. const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr)*)enclave_base;
  321. ElfW(Phdr) *phdr = get_phdr(ehdr);
  322. if (!init_array_addr || !init_array_size)
  323. return -1;
  324. if (phdr == NULL)
  325. return -1; /* Invalid image. */
  326. *init_array_addr = 0;
  327. *init_array_size = 0;
  328. /* Search for Dynamic segment */
  329. for (; phnum < ehdr->e_phnum; phnum++, phdr++)
  330. {
  331. if (phdr->p_type == PT_DYNAMIC)
  332. {
  333. size_t count;
  334. size_t n_dyn = phdr->p_filesz/sizeof(ElfW(Dyn));
  335. ElfW(Dyn) *dyn = GET_PTR(ElfW(Dyn), ehdr, phdr->p_paddr);
  336. for (count = 0; count < n_dyn; count++, dyn++)
  337. {
  338. switch (dyn->d_tag)
  339. {
  340. case DT_INIT_ARRAY:
  341. *init_array_addr = dyn->d_un.d_ptr;
  342. break;
  343. case DT_INIT_ARRAYSZ:
  344. *init_array_size = dyn->d_un.d_val;
  345. break;
  346. }
  347. }
  348. }
  349. }
  350. return 0;
  351. }
  352. /* vim: set ts=4 sw=4 et cin: */