/* * TODO(bsy): handle the !NACL_ABI_MAP_FIXED case. */ uintptr_t NaClHostDescMap(struct NaClHostDesc *d, void *start_addr, size_t len, int prot, int flags, nacl_off64_t offset) { int desc; void *map_addr; int host_prot; int host_flags; NaClLog(4, ("NaClHostDescMap(0x%08"NACL_PRIxPTR", " "0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxS", " "0x%x, 0x%x, 0x%08"NACL_PRIx64")\n"), (uintptr_t) d, (uintptr_t) start_addr, len, prot, flags, (int64_t) offset); if (NULL == d && 0 == (flags & NACL_ABI_MAP_ANONYMOUS)) { NaClLog(LOG_FATAL, "NaClHostDescMap: 'this' is NULL and not anon map\n"); } prot &= (NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE); /* may be PROT_NONE too, just not PROT_EXEC */ if (flags & NACL_ABI_MAP_ANONYMOUS) { desc = -1; } else { desc = d->d; } /* * Translate flags, prot to host_flags, host_prot. */ host_flags = NaClMapFlagMap(flags); host_prot = NaClProtMap(prot); NaClLog(4, "NaClHostDescMap: host_flags 0x%x, host_prot 0x%x\n", host_flags, host_prot); map_addr = mmap(start_addr, len, host_prot, host_flags, desc, offset); if (MAP_FAILED == map_addr) { NaClLog(LOG_INFO, ("NaClHostDescMap: " "mmap(0x%08"NACL_PRIxPTR", 0x%"NACL_PRIxS", " "0x%x, 0x%x, 0x%d, 0x%"NACL_PRIx64")" " failed, errno %d.\n"), (uintptr_t) start_addr, len, host_prot, host_flags, desc, (int64_t) offset, errno); return -NaClXlateErrno(errno); } if (0 != (flags & NACL_ABI_MAP_FIXED) && map_addr != start_addr) { NaClLog(LOG_FATAL, ("NaClHostDescMap: mmap with MAP_FIXED not fixed:" " returned 0x%08"NACL_PRIxPTR" instead of 0x%08"NACL_PRIxPTR"\n"), (uintptr_t) map_addr, (uintptr_t) start_addr); } NaClLog(4, "NaClHostDescMap: returning 0x%08"NACL_PRIxPTR"\n", (uintptr_t) start_addr); return (uintptr_t) start_addr; }
/* * TODO(bsy): handle the !NACL_ABI_MAP_FIXED case. */ uintptr_t NaClHostDescMap(struct NaClHostDesc *d, struct NaClDescEffector *effp, void *start_addr, size_t len, int prot, int flags, nacl_off64_t offset) { int desc; void *map_addr; int host_prot; int tmp_prot; int host_flags; int need_exec; UNREFERENCED_PARAMETER(effp); NaClLog(4, ("NaClHostDescMap(0x%08"NACL_PRIxPTR", " "0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxS", " "0x%x, 0x%x, 0x%08"NACL_PRIx64")\n"), (uintptr_t) d, (uintptr_t) start_addr, len, prot, flags, (int64_t) offset); if (NULL == d && 0 == (flags & NACL_ABI_MAP_ANONYMOUS)) { NaClLog(LOG_FATAL, "NaClHostDescMap: 'this' is NULL and not anon map\n"); } if (NULL != d && -1 == d->d) { NaClLog(LOG_FATAL, "NaClHostDescMap: already closed\n"); } if ((0 == (flags & NACL_ABI_MAP_SHARED)) == (0 == (flags & NACL_ABI_MAP_PRIVATE))) { NaClLog(LOG_FATAL, "NaClHostDescMap: exactly one of NACL_ABI_MAP_SHARED" " and NACL_ABI_MAP_PRIVATE must be set.\n"); } prot &= NACL_ABI_PROT_MASK; if (flags & NACL_ABI_MAP_ANONYMOUS) { desc = -1; } else { desc = d->d; } /* * Translate prot, flags to host_prot, host_flags. */ host_prot = NaClProtMap(prot); host_flags = NaClMapFlagMap(flags); NaClLog(4, "NaClHostDescMap: host_prot 0x%x, host_flags 0x%x\n", host_prot, host_flags); /* * In chromium-os, the /dev/shm and the user partition (where * installed apps live) are mounted no-exec, and a special * modification was made to the chromium-os version of the Linux * kernel to allow mmap to use files as backing store with * PROT_EXEC. The standard mmap code path will fail mmap requests * that ask for PROT_EXEC, but mprotect will allow chaning the * permissions later. This retains most of the defense-in-depth * property of disallowing PROT_EXEC in mmap, but enables the use * case of getting executable code from a file without copying. * * See https://code.google.com/p/chromium/issues/detail?id=202321 * for details of the chromium-os change. */ tmp_prot = host_prot & ~PROT_EXEC; need_exec = (0 != (PROT_EXEC & host_prot)); map_addr = mmap(start_addr, len, tmp_prot, host_flags, desc, offset); if (need_exec && MAP_FAILED != map_addr) { if (0 != mprotect(map_addr, len, host_prot)) { /* * Not being able to turn on PROT_EXEC is fatal: we have already * replaced the original mapping -- restoring them would be too * painful. Without scanning /proc (disallowed by outer * sandbox) or Mach's vm_region call, there is no way * simple/direct to figure out what was there before. On Linux * we could have mremap'd the old memory elsewhere, but still * would require probing to find the contiguous memory segments * within the original address range. And restoring dirtied * pages on OSX the mappings for which had disappeared may well * be impossible (getting clean copies of the pages is feasible, * but insufficient). */ NaClLog(LOG_FATAL, "NaClHostDescMap: mprotect to turn on PROT_EXEC failed," " errno %d\n", errno); } } NaClLog(4, "NaClHostDescMap: mmap returned %"NACL_PRIxPTR"\n", (uintptr_t) map_addr); if (MAP_FAILED == map_addr) { NaClLog(LOG_INFO, ("NaClHostDescMap: " "mmap(0x%08"NACL_PRIxPTR", 0x%"NACL_PRIxS", " "0x%x, 0x%x, 0x%d, 0x%"NACL_PRIx64")" " failed, errno %d.\n"), (uintptr_t) start_addr, len, host_prot, host_flags, desc, (int64_t) offset, errno); return -NaClXlateErrno(errno); } if (0 != (flags & NACL_ABI_MAP_FIXED) && map_addr != start_addr) { NaClLog(LOG_FATAL, ("NaClHostDescMap: mmap with MAP_FIXED not fixed:" " returned 0x%08"NACL_PRIxPTR" instead of 0x%08"NACL_PRIxPTR"\n"), (uintptr_t) map_addr, (uintptr_t) start_addr); } NaClLog(4, "NaClHostDescMap: returning 0x%08"NACL_PRIxPTR"\n", (uintptr_t) map_addr); return (uintptr_t) map_addr; }