/* protect user manifest and update mem_map */ static void ProtectUserManifest(struct NaClApp *nap, void *mft) { uintptr_t page_ptr; uint64_t size; size = FOURGIG - nap->stack_size - NaClSysToUser(nap, (uintptr_t)mft); page_ptr = AlignAndProtect((uintptr_t) mft, size, PROT_READ); /* update mem_map */ SET_MEM_MAP_IDX(nap->mem_map[SysDataIdx], "UserManifest", page_ptr, ROUNDUP_64K(size + ((uintptr_t)mft - page_ptr)), PROT_READ); /* its time to add hole to memory map */ page_ptr = nap->mem_map[HeapIdx].end; size = nap->mem_map[SysDataIdx].start - nap->mem_map[HeapIdx].end; SET_MEM_MAP_IDX(nap->mem_map[HoleIdx], "Hole", page_ptr, size, PROT_NONE); /* * patch: change the heap size to correct value. the user manifest * contains the different heap start (it does not include r/w data) * todo(d'b): fix it by adding a new memory region */ nap->mem_map[HeapIdx].size = nap->mem_map[HeapIdx].end - nap->mem_map[HeapIdx].start; }
/* protect bumpers (guarding space) */ static void NaClMprotectGuards(struct NaClApp *nap) { int err; ZLOGS(LOG_DEBUG, "Protecting bumpers"); /* * make bumpers (guard pages) with "inaccessible" protection. the "left" * bumper size is 40gb + 64kb, the "right" one - 40gb */ err = NaCl_mprotect((void *)(nap->mem_start - GUARDSIZE), GUARDSIZE + NACL_SYSCALL_START_ADDR, PROT_NONE); ZLOGFAIL(err != 0, err, FAILED_MSG); err = NaCl_mprotect((void *)(nap->mem_start + FOURGIG), GUARDSIZE, PROT_NONE); ZLOGFAIL(err != 0, err, FAILED_MSG); /* put information to the memory map */ SET_MEM_MAP_IDX(nap->mem_map[LeftBumperIdx], "LeftBumper", nap->mem_start - GUARDSIZE, GUARDSIZE + NACL_SYSCALL_START_ADDR, PROT_NONE); SET_MEM_MAP_IDX(nap->mem_map[RightBumperIdx], "RightBumper", nap->mem_start + FOURGIG, GUARDSIZE, PROT_NONE); }
/* * Apply memory protection to memory regions. */ void NaClMemoryProtection(struct NaClApp *nap) { uintptr_t start_addr; size_t region_size; int err; /* * The first NACL_SYSCALL_START_ADDR bytes are mapped as PROT_NONE. * This enables NULL pointer checking, and provides additional protection * against addr16/data16 prefixed operations being used for attacks. * * NaClMprotectGuards also sets up guard pages outside of the * virtual address space of the NaClApp -- for the ARM and x86-64 * where data sandboxing only sandbox memory writes and not reads, * we need to ensure that certain addressing modes that might * otherwise allow the NaCl app to write outside its address space * (given how we using masking / base registers to implement data * write sandboxing) won't affect the trusted data structures. */ ZLOGS(LOG_DEBUG, "Protecting guard pages for 0x%08x", nap->mem_start); NaClMprotectGuards(nap); start_addr = nap->mem_start + NACL_SYSCALL_START_ADDR; /* * The next pages up to NACL_TRAMPOLINE_END are the trampolines. * Immediately following that is the loaded text section. * These are collectively marked as PROT_READ | PROT_EXEC. */ region_size = NaClRoundPage(nap->static_text_end - NACL_SYSCALL_START_ADDR); ZLOGS(LOG_DEBUG, "Trampoline/text region start 0x%08x, size 0x%08x, end 0x%08x", start_addr, region_size, start_addr + region_size); err = NaCl_mprotect((void *)start_addr, region_size, PROT_READ | PROT_EXEC); ZLOGFAIL(0 != err, err, FAILED_MSG); SET_MEM_MAP_IDX(nap->mem_map[TextIdx], "Text", start_addr, region_size, PROT_READ | PROT_EXEC); /* * Page protections for this region have already been set up by * nacl_text.c. * * todo(d'b): since text.c exists no more, protection should be set here * * We record the mapping for consistency with other fixed * mappings, but the record is not actually used. Overmapping is * prevented by a separate range check, which is done by * NaClSysCommonAddrRangeContainsExecutablePages_mu(). */ /* * zerovm does not support dynamic text. the code below will check its * existence, log information and fail if needed. * todo(d'b): after the dynamic text support will be added or completely * removed the block below should be rewritten or removed */ start_addr = NaClUserToSys(nap, nap->dynamic_text_start); region_size = nap->dynamic_text_end - nap->dynamic_text_start; ZLOGS(LOG_DEBUG, "shm txt region start 0x%08x, size 0x%08x, end 0x%08x", start_addr, region_size, start_addr + region_size); ZLOGFAIL(0 != region_size, EFAULT, "zerovm does not support nexe with dynamic text!"); if(0 != nap->rodata_start) { uintptr_t rodata_end; /* * TODO(mseaborn): Could reduce the number of cases by ensuring * that nap->data_start is always non-zero, even if * nap->rodata_start == nap->data_start == nap->break_addr. */ if(0 != nap->data_start) rodata_end = nap->data_start; else rodata_end = nap->break_addr; start_addr = NaClUserToSys(nap, nap->rodata_start); region_size = NaClRoundPage(NaClRoundAllocPage(rodata_end) - NaClSysToUser(nap, start_addr)); ZLOGS(LOG_DEBUG, "RO data region start 0x%08x, size 0x%08x, end 0x%08x", start_addr, region_size, start_addr + region_size); err = NaCl_mprotect((void *)start_addr, region_size, PROT_READ); ZLOGFAIL(0 != err, err, FAILED_MSG); SET_MEM_MAP_IDX(nap->mem_map[RODataIdx], "ROData", start_addr, region_size, PROT_READ); } /* * data_end is max virtual addr seen, so start_addr <= data_end * must hold. */ if(0 != nap->data_start) { start_addr = NaClUserToSys(nap, nap->data_start); region_size = NaClRoundPage(NaClRoundAllocPage(nap->data_end) - NaClSysToUser(nap, start_addr)); ZLOGS(LOG_DEBUG, "RW data region start 0x%08x, size 0x%08x, end 0x%08x", start_addr, region_size, start_addr + region_size); err = NaCl_mprotect((void *)start_addr, region_size, PROT_READ | PROT_WRITE); ZLOGFAIL(0 != err, err, FAILED_MSG); SET_MEM_MAP_IDX(nap->mem_map[HeapIdx], "Heap", start_addr, region_size, PROT_READ | PROT_WRITE); } /* stack is read/write but not execute */ region_size = nap->stack_size; start_addr = NaClUserToSys(nap, NaClTruncAllocPage(((uintptr_t) 1U << nap->addr_bits) - nap->stack_size)); ZLOGS(LOG_DEBUG, "RW stack region start 0x%08x, size 0x%08lx, end 0x%08x", start_addr, region_size, start_addr + region_size); err = NaCl_mprotect((void *)start_addr, NaClRoundAllocPage(nap->stack_size), PROT_READ | PROT_WRITE); ZLOGFAIL(0 != err, err, FAILED_MSG); SET_MEM_MAP_IDX(nap->mem_map[StackIdx], "Stack", start_addr, NaClRoundAllocPage(nap->stack_size), PROT_READ | PROT_WRITE); }