Index: src/trusted/service_runtime/sel_ldr_standard.c |
=================================================================== |
--- src/trusted/service_runtime/sel_ldr_standard.c (revision 1006) |
+++ src/trusted/service_runtime/sel_ldr_standard.c (working copy) |
@@ -36,7 +36,6 @@ |
#include "native_client/src/include/portability.h" |
#include <stdio.h> |
- |
#include <stdlib.h> |
#include <string.h> |
@@ -49,6 +48,7 @@ |
#include "native_client/src/trusted/service_runtime/include/sys/errno.h" |
#include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h" |
+#include "native_client/src/trusted/service_runtime/elf_util.h" |
#include "native_client/src/trusted/service_runtime/nacl_app_thread.h" |
#include "native_client/src/trusted/service_runtime/nacl_check.h" |
#include "native_client/src/trusted/service_runtime/nacl_closure.h" |
@@ -61,286 +61,14 @@ |
#define PTR_ALIGN_MASK ((sizeof(void *))-1) |
-/* |
- * Other than empty segments, these are the only ones that are allowed. |
- */ |
-struct NaClPhdrChecks nacl_phdr_check_data[] = { |
- /* phdr */ |
- { PT_PHDR, PF_R, PCA_IGNORE, 0, 0, }, |
- /* text */ |
- { PT_LOAD, PF_R|PF_X, PCA_TEXT_CHECK, 1, NACL_TRAMPOLINE_END, }, |
- /* rodata */ |
- { PT_LOAD, PF_R, PCA_NONE, 0, 0, }, |
- /* data/bss */ |
- { PT_LOAD, PF_R|PF_W, PCA_NONE, 0, 0, }, |
-#if NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm |
- /* arm exception handling unwind info (for c++)*/ |
- /* TODO(robertm): for some reason this does NOT end up in ro maybe because |
- * it is relocatable. Try hacking the linker script to move it. |
- */ |
- { PT_ARM_EXIDX, PF_R, PCA_IGNORE, 0, 0, }, |
-#endif |
- /* |
- * allow optional GNU stack permission marker, but require that the |
- * stack is non-executable. |
- */ |
- { PT_GNU_STACK, PF_R|PF_W, PCA_NONE, 0, 0, }, |
-}; |
- |
-NaClErrorCode NaClProcessPhdrs(struct NaClApp *nap) { |
- /* Scan phdrs and do sanity checks in-line. Verify that the load |
- * address is NACL_TRAMPOLINE_END, that we have a single text |
- * segment. Data and TLS segments are not required, though it is |
- * hard to avoid with standard tools, but in any case there should |
- * be at most one each. Ensure that no segment's vaddr is outside |
- * of the address space. Ensure that PT_GNU_STACK is present, and |
- * that x is off. |
- */ |
- int seen_seg[NACL_ARRAY_SIZE(nacl_phdr_check_data)]; |
- |
- int segnum; |
- Elf32_Phdr *php; |
- size_t j; |
- uintptr_t max_vaddr; |
- |
- memset(seen_seg, 0, sizeof seen_seg); |
- max_vaddr = NACL_TRAMPOLINE_END; |
- /* |
- * nacl_phdr_check_data is small, so O(|check_data| * nap->elf_hdr.e_phum) |
- * is okay. |
- */ |
- for (segnum = 0; segnum < nap->elf_hdr.e_phnum; ++segnum) { |
- php = &nap->phdrs[segnum]; |
- NaClLog(3, "Looking at segment %d, type 0x%x, p_flags 0x%x\n", |
- segnum, php->p_type, php->p_flags); |
- php->p_flags &= ~PF_MASKOS; |
- for (j = 0; |
- j < NACL_ARRAY_SIZE(nacl_phdr_check_data); |
- ++j) { |
- if (php->p_type == nacl_phdr_check_data[j].p_type |
- && php->p_flags == nacl_phdr_check_data[j].p_flags) { |
- NaClLog(2, "Matched nacl_phdr_check_data[%"PRIdS"]\n", j); |
- if (seen_seg[j]) { |
- NaClLog(2, "Segment %d is a type that has been seen\n", segnum); |
- return LOAD_DUP_SEGMENT; |
- } |
- ++seen_seg[j]; |
- |
- if (PCA_IGNORE == nacl_phdr_check_data[j].action) { |
- NaClLog(3, "Ignoring\n"); |
- goto next_seg; |
- } |
- |
- if (0 != php->p_memsz) { |
- /* |
- * We will load this segment later. Do the sanity checks. |
- */ |
- if (0 != nacl_phdr_check_data[j].p_vaddr |
- && (nacl_phdr_check_data[j].p_vaddr != php->p_vaddr)) { |
- NaClLog(2, |
- ("Segment %d: bad virtual address: 0x%08x," |
- " expected 0x%08x\n"), |
- segnum, |
- php->p_vaddr, |
- nacl_phdr_check_data[j].p_vaddr); |
- return LOAD_SEGMENT_BAD_LOC; |
- } |
- if (php->p_vaddr < NACL_TRAMPOLINE_END) { |
- NaClLog(2, "Segment %d: virtual address (0x%08x) too low\n", |
- segnum, |
- php->p_vaddr); |
- return LOAD_SEGMENT_OUTSIDE_ADDRSPACE; |
- } |
- /* |
- * integer overflow? Elf32_Addr and Elf32_Word are uint32_t, |
- * so the addition/comparison is well defined. |
- */ |
- if (php->p_vaddr + php->p_memsz < php->p_vaddr) { |
- NaClLog(2, |
- "Segment %d: p_memsz caused integer overflow\n", |
- segnum); |
- return LOAD_SEGMENT_OUTSIDE_ADDRSPACE; |
- } |
- if (php->p_vaddr + php->p_memsz >= (1U << nap->addr_bits)) { |
- NaClLog(2, |
- "Segment %d: too large, ends at 0x%08x\n", |
- segnum, |
- php->p_vaddr + php->p_memsz); |
- return LOAD_SEGMENT_OUTSIDE_ADDRSPACE; |
- } |
- if (php->p_filesz > php->p_memsz) { |
- NaClLog(2, |
- ("Segment %d: file size 0x%08x larger" |
- " than memory size 0x%08x\n"), |
- segnum, |
- php->p_filesz, |
- php->p_memsz); |
- return LOAD_SEGMENT_BAD_PARAM; |
- } |
- |
- php->p_flags |= PF_OS_WILL_LOAD; |
- /* record our decision that we will load this segment */ |
- |
- /* |
- * NACL_TRAMPOLINE_END <= p_vaddr |
- * <= p_vaddr + p_memsz |
- * < (1U << nap->addr_bits) |
- */ |
- if (max_vaddr < php->p_vaddr + php->p_memsz) { |
- max_vaddr = php->p_vaddr + php->p_memsz; |
- } |
- } |
- |
- switch (nacl_phdr_check_data[j].action) { |
- case PCA_NONE: |
- break; |
- case PCA_TEXT_CHECK: |
- if (0 == php->p_memsz) { |
- return LOAD_BAD_ELF_TEXT; |
- } |
- nap->text_region_bytes = php->p_filesz; |
- break; |
- case PCA_IGNORE: |
- break; |
- } |
- goto next_seg; |
- } |
- } |
- /* segment not in nacl_phdr_check_data */ |
- if (0 == php->p_memsz) { |
- NaClLog(3, "Segment %d zero size: ignored\n", segnum); |
- continue; |
- } |
- NaClLog(2, |
- "Segment %d is of unexpected type 0x%x, flag 0x%x\n", |
- segnum, |
- php->p_type, |
- php->p_flags); |
- return LOAD_BAD_SEGMENT; |
- next_seg: |
- ; |
- } |
- for (j = 0; |
- j < NACL_ARRAY_SIZE(nacl_phdr_check_data); |
- ++j) { |
- if (nacl_phdr_check_data[j].required && !seen_seg[j]) { |
- return LOAD_REQUIRED_SEG_MISSING; |
- } |
- } |
- nap->data_end = nap->break_addr = max_vaddr; |
- /* |
- * Memory allocation will use NaClRoundPage(nap->break_addr), but |
- * the system notion of break is always an exact address. Even |
- * though we must allocate and make accessible multiples of pages, |
- * the linux-style brk system call (which returns current break on |
- * failure) permits an arbitrarily aligned address as argument. |
- */ |
- |
- return LOAD_OK; |
-} |
- |
- |
-static void NaClDumpElfHeader(Elf32_Ehdr *elf_hdr) { |
-#define DUMP(m,f) do { NaClLog(2, \ |
- #m " = %" f "\n", \ |
- elf_hdr->m); } while (0) |
- DUMP(e_ident+1, ".3s"); |
- DUMP(e_type, "#x"); |
- DUMP(e_machine, "#x"); |
- DUMP(e_version, "#x"); |
- DUMP(e_entry, "#x"); |
- DUMP(e_phoff, "#x"); |
- DUMP(e_shoff, "#x"); |
- DUMP(e_flags, "#x"); |
- DUMP(e_ehsize, "#x"); |
- DUMP(e_phentsize, "#x"); |
- DUMP(e_phnum, "#x"); |
- DUMP(e_shentsize, "#x"); |
- DUMP(e_shnum, "#x"); |
- DUMP(e_shstrndx, "#x"); |
-#undef DUMP |
- NaClLog(2, "sizeof(Elf32_Ehdr) = %x\n", (int) sizeof *elf_hdr); |
-} |
- |
- |
-static NaClErrorCode NaClValidateElfHeader(Elf32_Ehdr *hdr, |
- enum NaClAbiMismatchOption |
- abi_mismatch_option) { |
- if (memcmp(hdr->e_ident, ELFMAG, SELFMAG)) { |
- return LOAD_BAD_ELF_MAGIC; |
- } |
- if (ELFCLASS32 != hdr->e_ident[EI_CLASS]) { |
- return LOAD_NOT_32_BIT; |
- } |
- |
-#if !defined(DANGEROUS_DEBUG_MODE_DISABLE_INNER_SANDBOX) |
- if (ELFOSABI_NACL != hdr->e_ident[EI_OSABI]) { |
- NaClLog(LOG_ERROR, "Expected OSABI %d, got %d\n", |
- ELFOSABI_NACL, |
- hdr->e_ident[EI_OSABI]); |
- if (abi_mismatch_option == NACL_ABI_MISMATCH_OPTION_ABORT) { |
- return LOAD_BAD_ABI; |
- } |
- } |
- |
- if (EF_NACL_ABIVERSION != hdr->e_ident[EI_ABIVERSION]) { |
- NaClLog(LOG_ERROR, "Expected ABIVERSION %d, got %d\n", |
- EF_NACL_ABIVERSION, |
- hdr->e_ident[EI_ABIVERSION]); |
- if (abi_mismatch_option == NACL_ABI_MISMATCH_OPTION_ABORT) { |
- return LOAD_BAD_ABI; |
- } |
- } |
-#else |
- UNREFERENCED_PARAMETER(abi_mismatch_option); |
-#endif |
- |
- if (ET_EXEC != hdr->e_type) { |
- return LOAD_NOT_EXEC; |
- } |
- |
- if (EM_EXPECTED_BY_NACL != hdr->e_machine) { |
- return LOAD_BAD_MACHINE; |
- } |
- |
- if (EV_CURRENT != hdr->e_version) { |
- return LOAD_BAD_ELF_VERS; |
- } |
- |
- return LOAD_OK; |
-} |
- |
- |
-static void NaClDumpElfProgramHeader(Elf32_Phdr *phdr) { |
-#define DUMP(mem) do { \ |
- NaClLog(2, "%s: %x\n", #mem, phdr->mem); \ |
- } while (0) |
- |
- DUMP(p_type); |
- DUMP(p_offset); |
- DUMP(p_vaddr); |
- DUMP(p_paddr); |
- DUMP(p_filesz); |
- DUMP(p_memsz); |
- DUMP(p_flags); |
- NaClLog(2, " (%s %s %s)\n", |
- (phdr->p_flags & PF_R) ? "PF_R" : "", |
- (phdr->p_flags & PF_W) ? "PF_W" : "", |
- (phdr->p_flags & PF_X) ? "PF_X" : ""); |
- DUMP(p_align); |
-#undef DUMP |
- NaClLog(2, "\n"); |
-} |
- |
- |
-NaClErrorCode NaClAppLoadFile(struct Gio *gp, |
- struct NaClApp *nap, |
- enum NaClAbiMismatchOption abi_mismatch_option) { |
- NaClErrorCode ret = LOAD_INTERNAL; |
- NaClErrorCode subret; |
- int cur_ph; |
- |
+NaClErrorCode NaClAppLoadFile(struct Gio *gp, |
+ struct NaClApp *nap, |
+ enum NaClAbiCheckOption check_abi) { |
+ NaClErrorCode ret = LOAD_INTERNAL; |
+ NaClErrorCode subret; |
+ uintptr_t max_vaddr; |
+ struct NaClElfImage *image = NULL; |
/* NACL_MAX_ADDR_BITS < 32 */ |
if (nap->addr_bits > NACL_MAX_ADDR_BITS) { |
ret = LOAD_ADDR_SPACE_TOO_BIG; |
@@ -349,89 +77,58 @@ |
nap->stack_size = NaClRoundAllocPage(nap->stack_size); |
- /* nap->addr_bits <= NACL_MAX_ADDR_BITS < 32 */ |
- if ((*gp->vtbl->Read)(gp, |
- &nap->elf_hdr, |
- sizeof nap->elf_hdr) |
- != sizeof nap->elf_hdr) { |
- ret = LOAD_READ_ERROR; |
- goto done; |
- } |
+ /* temporay object will be deleted at end of function */ |
+ image = NaClElfImageNew(gp); |
+#if !defined(DANGEROUS_DEBUG_MODE_DISABLE_INNER_SANDBOX) |
+ check_abi = NACL_ABI_CHECK_OPTION_CHECK; |
+#endif |
- NaClDumpElfHeader(&nap->elf_hdr); |
- |
- subret = NaClValidateElfHeader(&nap->elf_hdr, abi_mismatch_option); |
- if (subret != LOAD_OK) { |
- ret = subret; |
- goto done; |
- } |
- |
- nap->entry_pt = nap->elf_hdr.e_entry; |
- |
- if (nap->elf_hdr.e_flags & EF_NACL_ALIGN_MASK) { |
- unsigned long eflags = nap->elf_hdr.e_flags & EF_NACL_ALIGN_MASK; |
- if (eflags == EF_NACL_ALIGN_16) { |
- nap->align_boundary = 16; |
- } else if (eflags == EF_NACL_ALIGN_32) { |
- nap->align_boundary = 32; |
- } else { |
- ret = LOAD_BAD_ABI; |
+ if (check_abi == NACL_ABI_CHECK_OPTION_CHECK) { |
+ subret = NaClElfImageValidateAbi(image); |
+ if (subret != LOAD_OK) { |
+ ret = subret; |
goto done; |
} |
- } else { |
- nap->align_boundary = 32; |
+ |
} |
- /* read program headers */ |
- if (nap->elf_hdr.e_phnum > NACL_MAX_PROGRAM_HEADERS) { |
- ret = LOAD_TOO_MANY_SECT; /* overloaded */ |
+ subret = NaClElfImageValidateElfHeader(image); |
+ if (subret != LOAD_OK) { |
+ ret = subret; |
goto done; |
} |
- /* TODO(robertm): determine who allocated this */ |
- free(nap->phdrs); |
- |
- nap->phdrs = malloc(nap->elf_hdr.e_phnum * sizeof nap->phdrs[0]); |
- if (!nap->phdrs) { |
- ret = LOAD_NO_MEMORY; |
+ subret = NaClElfImageValidateProgramHeaders(image, |
+ nap->addr_bits, |
+ &nap->text_region_bytes, |
+ &max_vaddr); |
+ if (subret != LOAD_OK) { |
+ ret = subret; |
goto done; |
} |
- if (nap->elf_hdr.e_phentsize < sizeof nap->phdrs[0]) { |
- ret = LOAD_BAD_SECT; |
- goto done; |
- } |
- for (cur_ph = 0; cur_ph < nap->elf_hdr.e_phnum; ++cur_ph) { |
- if ((*gp->vtbl->Seek)(gp, |
- nap->elf_hdr.e_phoff |
- + cur_ph * nap->elf_hdr.e_phentsize, |
- SEEK_SET) == -1) { |
- ret = LOAD_BAD_SECT; |
- goto done; |
- } |
- if ((*gp->vtbl->Read)(gp, |
- &nap->phdrs[cur_ph], |
- sizeof nap->phdrs[0]) |
- != sizeof nap->phdrs[0]) { |
- ret = LOAD_BAD_SECT; |
- goto done; |
- } |
+ nap->break_addr = max_vaddr; |
+ nap->data_end = max_vaddr; |
- NaClDumpElfProgramHeader(&nap->phdrs[cur_ph]); |
- } |
- |
- /* |
- * We need to determine the size of the CS region. (The DS and SS |
- * region sizes are obvious -- the entire application address |
- * space.) NaClProcessPhdrs will figure out nap->text_region_bytes. |
- */ |
- |
- subret = NaClProcessPhdrs(nap); |
- if (subret != LOAD_OK) { |
- ret = subret; |
+ nap->align_boundary = NaClElfImageGetAlignBoundary(image); |
+ if (nap->align_boundary == 0) { |
+ ret = LOAD_BAD_ABI; |
goto done; |
} |
+ nap->entry_pt = NaClElfImageGetEntryPoint(image); |
+ |
+ NaClLog(2, |
+ "text_region_bytes: %08x " |
+ "break_add: %08"PRIxPTR" " |
+ "data_end: %08"PRIxPTR" " |
+ "entry_pt: %08x " |
+ "align_boundary: %08x\n", |
+ nap->text_region_bytes, |
+ nap->break_addr, |
+ nap->data_end, |
+ nap->entry_pt, |
+ nap->align_boundary); |
if (!NaClAddrIsValidEntryPt(nap, nap->entry_pt)) { |
ret = LOAD_BAD_ENTRY; |
goto done; |
@@ -445,12 +142,14 @@ |
} |
NaClLog(2, "Loading into memory\n"); |
- subret = NaClLoadImage(gp, nap); |
+ subret = NaClElfImageLoad(image, gp, nap->addr_bits, nap->mem_start); |
if (subret != LOAD_OK) { |
ret = subret; |
goto done; |
} |
+ NaClFillEndOfTextRegion(nap); |
+ |
#if !defined(DANGEROUS_DEBUG_MODE_DISABLE_INNER_SANDBOX) |
NaClLog(2, "Validating image\n"); |
subret = NaClValidateImage(nap); |
@@ -487,6 +186,7 @@ |
ret = LOAD_OK; |
done: |
+ NaClElfImageDelete(image); |
return ret; |
} |
@@ -615,7 +315,7 @@ |
if (!NaClAppThreadAllocSegCtor(natp, |
nap, |
1, |
- nap->elf_hdr.e_entry, |
+ nap->entry_pt, |
NaClSysToUser(nap, stack_ptr), |
NaClUserToSys(nap, nap->break_addr), |
1)) { |