/* * Basic address space layout sanity check. */ NaClErrorCode NaClCheckAddressSpaceLayoutSanity(struct NaClApp *nap, uintptr_t rodata_end, uintptr_t data_end, uintptr_t max_vaddr) { if (0 != nap->data_start) { if (data_end != max_vaddr) { NaClLog(LOG_INFO, "data segment is not last\n"); return LOAD_DATA_NOT_LAST_SEGMENT; } } else if (0 != nap->rodata_start) { if (NaClRoundAllocPage(rodata_end) != max_vaddr) { /* * This should be unreachable, but we include it just for * completeness. * * Here is why it is unreachable: * * NaClPhdrChecks checks the test segment starting address. The * only allowed loaded segments are text, data, and rodata. * Thus unless the rodata is in the trampoline region, it must * be after the text. And NaClElfImageValidateProgramHeaders * ensures that all segments start after the trampoline region. */ NaClLog(LOG_INFO, "no data segment, but rodata segment is not last\n"); return LOAD_NO_DATA_BUT_RODATA_NOT_LAST_SEGMENT; } } if (0 != nap->rodata_start && 0 != nap->data_start) { if (rodata_end > nap->data_start) { NaClLog(LOG_INFO, "rodata_overlaps data.\n"); return LOAD_RODATA_OVERLAPS_DATA; } } if (0 != nap->rodata_start) { if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) > nap->rodata_start) { return LOAD_TEXT_OVERLAPS_RODATA; } } else if (0 != nap->data_start) { if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) > nap->data_start) { return LOAD_TEXT_OVERLAPS_DATA; } } if (0 != nap->rodata_start && NaClRoundAllocPage(nap->rodata_start) != nap->rodata_start) { NaClLog(LOG_INFO, "rodata_start not a multiple of allocation size\n"); return LOAD_BAD_RODATA_ALIGNMENT; } if (0 != nap->data_start && NaClRoundAllocPage(nap->data_start) != nap->data_start) { NaClLog(LOG_INFO, "data_start not a multiple of allocation size\n"); return LOAD_BAD_DATA_ALIGNMENT; } return LOAD_OK; }
/* Basic address space layout sanity check */ static void CheckAddressSpaceLayoutSanity(struct NaClApp *nap, uintptr_t rodata_end, uintptr_t data_end, uintptr_t max_vaddr) { /* fail if Data segment exists, but is not last segment */ if(0 != nap->data_start) ZLOGFAIL(data_end != max_vaddr, ENOEXEC, FAILED_MSG); /* * This should be unreachable, but we include it just for completeness * * Here is why it is unreachable: * * PhdrChecks checks the test segment starting address. The * only allowed loaded segments are text, data, and rodata. * Thus unless the rodata is in the trampoline region, it must * be after the text. And ValidateProgramHeaders ensures that * all segments start after the trampoline region. * * d'b: fail if no data segment. read-only data segment exists * but is not last segment */ else if(0 != nap->rodata_start) ZLOGFAIL(ROUNDUP_64K(rodata_end) != max_vaddr, ENOEXEC, FAILED_MSG); /* fail if Read-only data segment overlaps data segment */ if(0 != nap->rodata_start && 0 != nap->data_start) ZLOGFAIL(rodata_end > nap->data_start, ENOEXEC, FAILED_MSG); /* fail if Text segment overlaps rodata segment */ if(0 != nap->rodata_start) ZLOGFAIL(ROUNDUP_64K(NaClEndOfStaticText(nap)) > nap->rodata_start, ENOEXEC, FAILED_MSG); /* fail if No rodata segment, and text segment overlaps data segment */ else if(0 != nap->data_start) ZLOGFAIL(ROUNDUP_64K(NaClEndOfStaticText(nap)) > nap->data_start, ENOEXEC, FAILED_MSG); /* fail if rodata_start not a multiple of allocation size */ ZLOGFAIL(0 != nap->rodata_start && ROUNDUP_64K(nap->rodata_start) != nap->rodata_start, ENOEXEC, FAILED_MSG); /* fail if data_start not a multiple of allocation size */ ZLOGFAIL(0 != nap->data_start && ROUNDUP_64K(nap->data_start) != nap->data_start, ENOEXEC, FAILED_MSG); }
void NaClAppPrintDetails(struct NaClApp *nap, struct Gio *gp, int verbosity) { ZLOGS(verbosity, "NaClAppPrintDetails((struct NaClApp *) 0x%08lx," "(struct Gio *) 0x%08lx)", (uintptr_t)nap, (uintptr_t)gp); ZLOGS(verbosity, "addr space size: 2**%d", nap->addr_bits); ZLOGS(verbosity, "stack size: 0x%08d", nap->stack_size); ZLOGS(verbosity, "mem start addr: 0x%08lx", nap->mem_start); ZLOGS(verbosity, "static_text_end: 0x%08lx", nap->static_text_end); ZLOGS(verbosity, "end-of-text: 0x%08lx", NaClEndOfStaticText(nap)); ZLOGS(verbosity, "rodata: 0x%08lx", nap->rodata_start); ZLOGS(verbosity, "data: 0x%08lx", nap->data_start); ZLOGS(verbosity, "data_end: 0x%08lx", nap->data_end); ZLOGS(verbosity, "break_addr: 0x%08lx", nap->break_addr); ZLOGS(verbosity, "ELF initial entry point: 0x%08x", nap->initial_entry_pt); ZLOGS(verbosity, "ELF user entry point: 0x%08x", nap->user_entry_pt); }
NaClErrorCode NaClAppLoadFile(struct Gio *gp, struct NaClApp *nap, enum NaClAbiCheckOption check_abi) { NaClErrorCode ret = LOAD_INTERNAL; NaClErrorCode subret; uintptr_t rodata_end; uintptr_t data_end; 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; goto done; } nap->stack_size = NaClRoundAllocPage(nap->stack_size); /* temporay object will be deleted at end of function */ image = NaClElfImageNew(gp, &subret); if (NULL == image) { ret = subret; goto done; } #if 0 == NACL_DANGEROUS_DEBUG_MODE_DISABLE_INNER_SANDBOX check_abi = NACL_ABI_CHECK_OPTION_CHECK; #endif if (NACL_ABI_CHECK_OPTION_CHECK == check_abi) { subret = NaClElfImageValidateAbi(image); if (subret != LOAD_OK) { ret = subret; goto done; } } subret = NaClElfImageValidateElfHeader(image); if (LOAD_OK != subret) { ret = subret; goto done; } subret = NaClElfImageValidateProgramHeaders(image, nap->addr_bits, &nap->static_text_end, &nap->rodata_start, &rodata_end, &nap->data_start, &data_end, &max_vaddr); if (LOAD_OK != subret) { ret = subret; goto done; } if (0 == nap->data_start) { if (0 == nap->rodata_start) { if (NaClRoundAllocPage(max_vaddr) - max_vaddr < NACL_HALT_SLED_SIZE) { /* * if no rodata and no data, we make sure that there is space for * the halt sled. */ max_vaddr += NACL_MAP_PAGESIZE; } } else { /* * no data, but there is rodata. this means max_vaddr is just * where rodata ends. this might not be at an allocation * boundary, and in this the page would not be writable. round * max_vaddr up to the next allocation boundary so that bss will * be at the next writable region. */ ; } max_vaddr = NaClRoundAllocPage(max_vaddr); } /* * max_vaddr -- the break or the boundary between data (initialized * and bss) and the address space hole -- does not have to be at a * page boundary. */ nap->break_addr = max_vaddr; nap->data_end = max_vaddr; NaClLog(4, "Values from NaClElfImageValidateProgramHeaders:\n"); NaClLog(4, "rodata_start = 0x%08"NACL_PRIxPTR"\n", nap->rodata_start); NaClLog(4, "rodata_end = 0x%08"NACL_PRIxPTR"\n", rodata_end); NaClLog(4, "data_start = 0x%08"NACL_PRIxPTR"\n", nap->data_start); NaClLog(4, "data_end = 0x%08"NACL_PRIxPTR"\n", data_end); NaClLog(4, "max_vaddr = 0x%08"NACL_PRIxPTR"\n", max_vaddr); #if 0 == NACL_DANGEROUS_DEBUG_MODE_DISABLE_INNER_SANDBOX nap->bundle_size = NaClElfImageGetBundleSize(image); if (nap->bundle_size == 0) { ret = LOAD_BAD_ABI; goto done; } #else /* pick some reasonable default for an un-sandboxed nexe */ nap->bundle_size = 32; #endif nap->entry_pt = NaClElfImageGetEntryPoint(image); NaClLog(2, "NaClApp addr space layout:\n"); NaClLog(2, "nap->static_text_end = 0x%016"NACL_PRIxPTR"\n", nap->static_text_end); NaClLog(2, "nap->dynamic_text_start = 0x%016"NACL_PRIxPTR"\n", nap->dynamic_text_start); NaClLog(2, "nap->dynamic_text_end = 0x%016"NACL_PRIxPTR"\n", nap->dynamic_text_end); NaClLog(2, "nap->rodata_start = 0x%016"NACL_PRIxPTR"\n", nap->rodata_start); NaClLog(2, "nap->data_start = 0x%016"NACL_PRIxPTR"\n", nap->data_start); NaClLog(2, "nap->data_end = 0x%016"NACL_PRIxPTR"\n", nap->data_end); NaClLog(2, "nap->break_addr = 0x%016"NACL_PRIxPTR"\n", nap->break_addr); NaClLog(2, "nap->entry_pt = 0x%016"NACL_PRIxPTR"\n", nap->entry_pt); NaClLog(2, "nap->bundle_size = 0x%x\n", nap->bundle_size); if (!NaClAddrIsValidEntryPt(nap, nap->entry_pt)) { ret = LOAD_BAD_ENTRY; goto done; } /* * Basic address space layout sanity check. */ if (0 != nap->data_start) { if (data_end != max_vaddr) { NaClLog(LOG_INFO, "data segment is not last\n"); ret = LOAD_DATA_NOT_LAST_SEGMENT; goto done; } } else if (0 != nap->rodata_start) { if (NaClRoundAllocPage(rodata_end) != max_vaddr) { /* * This should be unreachable, but we include it just for * completeness. * * Here is why it is unreachable: * * NaClPhdrChecks checks the test segment starting address. The * only allowed loaded segments are text, data, and rodata. * Thus unless the rodata is in the trampoline region, it must * be after the text. And NaClElfImageValidateProgramHeaders * ensures that all segments start after the trampoline region. */ NaClLog(LOG_INFO, "no data segment, but rodata segment is not last\n"); ret = LOAD_NO_DATA_BUT_RODATA_NOT_LAST_SEGMENT; goto done; } } if (0 != nap->rodata_start && 0 != nap->data_start) { if (rodata_end > nap->data_start) { NaClLog(LOG_INFO, "rodata_overlaps data.\n"); ret = LOAD_RODATA_OVERLAPS_DATA; goto done; } } if (0 != nap->rodata_start) { if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) > nap->rodata_start) { ret = LOAD_TEXT_OVERLAPS_RODATA; goto done; } } else if (0 != nap->data_start) { if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) > nap->data_start) { ret = LOAD_TEXT_OVERLAPS_DATA; goto done; } } if (0 != nap->rodata_start && NaClRoundAllocPage(nap->rodata_start) != nap->rodata_start) { NaClLog(LOG_INFO, "rodata_start not a multiple of allocation size\n"); ret = LOAD_BAD_RODATA_ALIGNMENT; goto done; } if (0 != nap->data_start && NaClRoundAllocPage(nap->data_start) != nap->data_start) { NaClLog(LOG_INFO, "data_start not a multiple of allocation size\n"); ret = LOAD_BAD_DATA_ALIGNMENT; goto done; } NaClLog(2, "Allocating address space\n"); subret = NaClAllocAddrSpace(nap); if (LOAD_OK != subret) { ret = subret; goto done; } /* * NB: mem_map object has been initialized, but is empty. * NaClMakeDynamicTextShared does not touch it. * * NaClMakeDynamicTextShared also fills the dynamic memory region * with the architecture-specific halt instruction. If/when we use * memory mapping to save paging space for the dynamic region and * lazily halt fill the memory as the pages become * readable/executable, we must make sure that the *last* * NACL_MAP_PAGESIZE chunk is nonetheless mapped and written with * halts. */ NaClLog(2, ("Replacing gap between static text and" " (ro)data with shareable memory\n")); subret = NaClMakeDynamicTextShared(nap); if (LOAD_OK != subret) { ret = subret; goto done; } /* * Make sure the static image pages are marked writable before we try * to write them. * TODO(ilewis): See if this can be enabled for Win32 as well. (issue 40077) */ NaClLog(2, "Loading into memory\n"); #if NACL_WINDOWS && NACL_ARCH_CPU_X86_64 ret = NaCl_mprotect((void*) nap->mem_start, NaClRoundAllocPage(nap->data_end), PROT_READ|PROT_WRITE); if (ret) { NaClLog(LOG_FATAL, "Couldn't get writeable pages for image. " "Error code 0x%X\n", ret); } #endif subret = NaClElfImageLoad(image, gp, nap->addr_bits, nap->mem_start); if (LOAD_OK != subret) { ret = subret; goto done; } /* * NaClFillEndOfTextRegion will fill with halt instructions the * padding space after the static text region. * * Shm-backed dynamic text space was filled with halt instructions * in NaClMakeDynamicTextShared. This extends to the rodata. For * non-shm-backed text space, this extend to the next page (and not * allocation page). static_text_end is updated to include the * padding. */ NaClFillEndOfTextRegion(nap); #if 0 == NACL_DANGEROUS_DEBUG_MODE_DISABLE_INNER_SANDBOX NaClLog(2, "Validating image\n"); subret = NaClValidateImage(nap); if (LOAD_OK != subret) { ret = subret; goto done; } #endif NaClLog(2, "Installing trampoline\n"); NaClLoadTrampoline(nap); NaClLog(2, "Installing springboard\n"); NaClLoadSpringboard(nap); NaClLog(2, "Applying memory protection\n"); /* * NaClMemoryProtect also initializes the mem_map w/ information * about the memory pages and their current protection value. * * The contents of the dynamic text region will get remapped as * non-writable. */ subret = NaClMemoryProtection(nap); if (LOAD_OK != subret) { ret = subret; goto done; } NaClLog(2, "NaClAppLoadFile done; addr space layout:\n"); NaClLog(2, "nap->static_text_end = 0x%016"NACL_PRIxPTR"\n", nap->static_text_end); NaClLog(2, "nap->dynamic_text_start = 0x%016"NACL_PRIxPTR"\n", nap->dynamic_text_start); NaClLog(2, "nap->dynamic_text_end = 0x%016"NACL_PRIxPTR"\n", nap->dynamic_text_end); NaClLog(2, "nap->rodata_start = 0x%016"NACL_PRIxPTR"\n", nap->rodata_start); NaClLog(2, "nap->data_start = 0x%016"NACL_PRIxPTR"\n", nap->data_start); NaClLog(2, "nap->data_end = 0x%016"NACL_PRIxPTR"\n", nap->data_end); NaClLog(2, "nap->break_addr = 0x%016"NACL_PRIxPTR"\n", nap->break_addr); NaClLog(2, "nap->entry_pt = 0x%016"NACL_PRIxPTR"\n", nap->entry_pt); NaClLog(2, "nap->bundle_size = 0x%x\n", nap->bundle_size); ret = LOAD_OK; done: NaClElfImageDelete(image); return ret; }
/* * Basic address space layout sanity check. */ NaClErrorCode NaClCheckAddressSpaceLayoutSanity(struct NaClApp *nap, uintptr_t rodata_end, uintptr_t data_end, uintptr_t max_vaddr) { if (0 != nap->data_start) { if (data_end != max_vaddr) { NaClLog(LOG_INFO, "data segment is not last\n"); return LOAD_DATA_NOT_LAST_SEGMENT; } } else if (0 != nap->rodata_start) { if (NaClRoundAllocPage(rodata_end) != max_vaddr) { /* * This should be unreachable, but we include it just for * completeness. * * Here is why it is unreachable: * * NaClPhdrChecks checks the test segment starting address. The * only allowed loaded segments are text, data, and rodata. * Thus unless the rodata is in the trampoline region, it must * be after the text. And NaClElfImageValidateProgramHeaders * ensures that all segments start after the trampoline region. */ NaClLog(LOG_INFO, "no data segment, but rodata segment is not last\n"); return LOAD_NO_DATA_BUT_RODATA_NOT_LAST_SEGMENT; } } if (0 != nap->rodata_start && 0 != nap->data_start) { if (rodata_end > NaClTruncAllocPage(nap->data_start)) { NaClLog(LOG_INFO, "rodata_overlaps data.\n"); return LOAD_RODATA_OVERLAPS_DATA; } } if (0 != nap->rodata_start) { if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) > nap->rodata_start) { return LOAD_TEXT_OVERLAPS_RODATA; } } else if (0 != nap->data_start) { if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) > NaClTruncAllocPage(nap->data_start)) { return LOAD_TEXT_OVERLAPS_DATA; } } if (0 != nap->rodata_start && NaClRoundAllocPage(nap->rodata_start) != nap->rodata_start) { NaClLog(LOG_INFO, "rodata_start not a multiple of allocation size\n"); return LOAD_BAD_RODATA_ALIGNMENT; } #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips /* * This check is necessary to make MIPS sandbox secure, as there is no NX page * protection support on MIPS. */ if (nap->rodata_start < NACL_DATA_SEGMENT_START) { NaClLog(LOG_INFO, "rodata_start is below NACL_DATA_SEGMENT_START (0x%X) address\n", NACL_DATA_SEGMENT_START); return LOAD_SEGMENT_BAD_LOC; } #endif return LOAD_OK; }
NaClErrorCode NaClMakeDynamicTextShared(struct NaClApp *nap) { enum NaClErrorCode retval = LOAD_INTERNAL; uintptr_t dynamic_text_size; struct NaClDescImcShm *shm = NULL; uintptr_t shm_vaddr_base; int mmap_protections; uintptr_t mmap_ret; uintptr_t shm_upper_bound; uintptr_t text_sysaddr; shm_vaddr_base = NaClEndOfStaticText(nap); NaClLog(4, "NaClMakeDynamicTextShared: shm_vaddr_base = %08"NACL_PRIxPTR"\n", shm_vaddr_base); shm_vaddr_base = NaClRoundAllocPage(shm_vaddr_base); NaClLog(4, "NaClMakeDynamicTextShared: shm_vaddr_base = %08"NACL_PRIxPTR"\n", shm_vaddr_base); /* * Default is that there is no usable dynamic code area. */ nap->dynamic_text_start = shm_vaddr_base; nap->dynamic_text_end = shm_vaddr_base; if (!nap->use_shm_for_dynamic_text) { NaClLog(4, "NaClMakeDynamicTextShared:" " rodata / data segments not allocation aligned\n"); NaClLog(4, " not using shm for text\n"); return LOAD_OK; } /* * Allocate a shm region the size of which is nap->rodata_start - * end-of-text. This implies that the "core" text will not be * backed by shm. */ shm_upper_bound = nap->rodata_start; if (0 == shm_upper_bound) { shm_upper_bound = NaClTruncAllocPage(nap->data_start); } if (0 == shm_upper_bound) { shm_upper_bound = shm_vaddr_base; } NaClLog(4, "shm_upper_bound = %08"NACL_PRIxPTR"\n", shm_upper_bound); dynamic_text_size = shm_upper_bound - shm_vaddr_base; NaClLog(4, "NaClMakeDynamicTextShared: dynamic_text_size = %"NACL_PRIxPTR"\n", dynamic_text_size); if (0 == dynamic_text_size) { NaClLog(4, "Empty JITtable region\n"); return LOAD_OK; } shm = (struct NaClDescImcShm *) malloc(sizeof *shm); if (NULL == shm) { NaClLog(4, "NaClMakeDynamicTextShared: shm object allocation failed\n"); retval = LOAD_NO_MEMORY; goto cleanup; } if (!NaClDescImcShmAllocCtor(shm, dynamic_text_size, /* executable= */ 1)) { /* cleanup invariant is if ptr is non-NULL, it's fully ctor'd */ free(shm); shm = NULL; NaClLog(4, "NaClMakeDynamicTextShared: shm alloc ctor for text failed\n"); retval = LOAD_NO_MEMORY_FOR_DYNAMIC_TEXT; goto cleanup; } text_sysaddr = NaClUserToSys(nap, shm_vaddr_base); /* Existing memory is anonymous paging file backed. */ NaClPageFree((void *) text_sysaddr, dynamic_text_size); /* * Unix allows us to map pages with PROT_NONE initially and later * increase the mapping permissions with mprotect(). * * Windows does not allow this, however: the initial permissions are * an upper bound on what the permissions may later be changed to * with VirtualProtect() or VirtualAlloc(). Given this, using * PROT_NONE at this point does not even make sense. On Windows, * the pages start off as uncommitted, which makes them inaccessible * regardless of the page permissions they are mapped with. * * Write permissions are included here for nacl64-gdb to set * breakpoints. */ #if NACL_WINDOWS mmap_protections = NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC | NACL_ABI_PROT_WRITE; #else mmap_protections = NACL_ABI_PROT_NONE; #endif NaClLog(4, "NaClMakeDynamicTextShared: Map(,,0x%"NACL_PRIxPTR",size = 0x%x," " prot=0x%x, flags=0x%x, offset=0)\n", text_sysaddr, (int) dynamic_text_size, mmap_protections, NACL_ABI_MAP_SHARED | NACL_ABI_MAP_FIXED); mmap_ret = (*((struct NaClDescVtbl const *) shm->base.base.vtbl)-> Map)((struct NaClDesc *) shm, NaClDescEffectorTrustedMem(), (void *) text_sysaddr, dynamic_text_size, mmap_protections, NACL_ABI_MAP_SHARED | NACL_ABI_MAP_FIXED, 0); if (text_sysaddr != mmap_ret) { NaClLog(LOG_FATAL, "Could not map in shm for dynamic text region\n"); } nap->dynamic_page_bitmap = BitmapAllocate((uint32_t) (dynamic_text_size / NACL_MAP_PAGESIZE)); if (NULL == nap->dynamic_page_bitmap) { NaClLog(LOG_FATAL, "NaClMakeDynamicTextShared: BitmapAllocate() failed\n"); } nap->dynamic_text_start = shm_vaddr_base; nap->dynamic_text_end = shm_upper_bound; nap->text_shm = &shm->base; retval = LOAD_OK; cleanup: if (LOAD_OK != retval) { NaClDescSafeUnref((struct NaClDesc *) shm); free(shm); } return retval; }
void AppLoadFile(struct Gio *gp, struct NaClApp *nap) { uintptr_t rodata_end; uintptr_t data_end; uintptr_t max_vaddr; struct ElfImage *image = NULL; int err; /* fail if Address space too big */ ZLOGFAIL(nap->addr_bits > NACL_MAX_ADDR_BITS, EFAULT, FAILED_MSG); nap->stack_size = ROUNDUP_64K(nap->stack_size); /* temporay object will be deleted at end of function */ image = ElfImageNew(gp); ValidateElfHeader(image); ValidateProgramHeaders(image, nap->addr_bits, &nap->static_text_end, &nap->rodata_start, &rodata_end, &nap->data_start, &data_end, &max_vaddr); /* * if no rodata and no data, we make sure that there is space for * the halt sled. else if no data, but there is rodata. this means * max_vaddr is just where rodata ends. this might not be at an * allocation boundary, and in this the page would not be writable. * round max_vaddr up to the next allocation boundary so that bss * will be at the next writable region. */ if(0 == nap->data_start) { if(0 == nap->rodata_start) { if(ROUNDUP_64K(max_vaddr) - max_vaddr < NACL_HALT_SLED_SIZE) max_vaddr += NACL_MAP_PAGESIZE; } max_vaddr = ROUNDUP_64K(max_vaddr); } /* * max_vaddr -- the break or the boundary between data (initialized * and bss) and the address space hole -- does not have to be at a * page boundary. */ nap->break_addr = max_vaddr; nap->data_end = max_vaddr; ZLOGS(LOG_INSANE, "Values from ValidateProgramHeaders:"); DUMP(nap->rodata_start); DUMP(rodata_end); DUMP(nap->data_start); DUMP(data_end); DUMP(max_vaddr); nap->initial_entry_pt = ElfImageGetEntryPoint(image); LogAddressSpaceLayout(nap); /* Bad program entry point address */ ZLOGFAIL(!AddrIsValidEntryPt(nap, nap->initial_entry_pt), ENOEXEC, FAILED_MSG); CheckAddressSpaceLayoutSanity(nap, rodata_end, data_end, max_vaddr); ZLOGS(LOG_DEBUG, "Allocating address space"); AllocAddrSpace(nap); /* * Make sure the static image pages are marked writable before we try * to write them. */ ZLOGS(LOG_DEBUG, "Loading into memory"); err = NaCl_mprotect((void *)(nap->mem_start + NACL_TRAMPOLINE_START), ROUNDUP_64K(nap->data_end) - NACL_TRAMPOLINE_START, PROT_READ | PROT_WRITE); ZLOGFAIL(0 != err, EFAULT, "Failed to make image pages writable. errno = %d", err); ElfImageLoad(image, gp, nap->addr_bits, nap->mem_start); /* d'b: shared memory for the dynamic text disabled */ nap->dynamic_text_start = ROUNDUP_64K(NaClEndOfStaticText(nap)); nap->dynamic_text_end = nap->dynamic_text_start; /* * FillEndOfTextRegion will fill with halt instructions the * padding space after the static text region. * * Shm-backed dynamic text space was filled with halt instructions * in NaClMakeDynamicTextShared. This extends to the rodata. For * non-shm-backed text space, this extend to the next page (and not * allocation page). static_text_end is updated to include the * padding. */ FillEndOfTextRegion(nap); ZLOGS(LOG_DEBUG, "Initializing arch switcher"); InitSwitchToApp(nap); ZLOGS(LOG_DEBUG, "Installing trampoline"); LoadTrampoline(nap); /* * NaClMemoryProtect also initializes the mem_map w/ information * about the memory pages and their current protection value. * * The contents of the dynamic text region will get remapped as * non-writable. */ ZLOGS(LOG_DEBUG, "Applying memory protection"); MemoryProtection(nap); ZLOGS(LOG_DEBUG, "AppLoadFile done"); LogAddressSpaceLayout(nap); ElfImageDelete(image); }