static uintptr_t NaClDescImcShmMap(struct NaClDesc *vself, struct NaClDescEffector *effp, void *start_addr, size_t len, int prot, int flags, nacl_off64_t offset) { struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself; int rv; int nacl_imc_prot; int nacl_imc_flags; uintptr_t addr; uintptr_t end_addr; void *result; nacl_off64_t tmp_off64; off_t tmp_off; NaClLog(4, "NaClDescImcShmMmap(,,0x%08"NACL_PRIxPTR",0x%"NACL_PRIxS"," "0x%x,0x%x,0x%08"NACL_PRIxNACL_OFF64")\n", (uintptr_t) start_addr, len, prot, flags, offset); /* * shm must have NACL_ABI_MAP_SHARED in flags, and all calls through * this API must supply a start_addr, so NACL_ABI_MAP_FIXED is * assumed. */ if (NACL_ABI_MAP_SHARED != (flags & NACL_ABI_MAP_SHARING_MASK)) { NaClLog(LOG_INFO, ("NaClDescImcShmMap: Mapping not NACL_ABI_MAP_SHARED," " flags 0x%x\n"), flags); return -NACL_ABI_EINVAL; } if (0 != (NACL_ABI_MAP_FIXED & flags) && NULL == start_addr) { NaClLog(LOG_INFO, ("NaClDescImcShmMap: Mapping NACL_ABI_MAP_FIXED" " but start_addr is NULL\n")); } /* post-condition: if NULL == start_addr, then NACL_ABI_MAP_FIXED not set */ /* * prot must not contain bits other than PROT_{READ|WRITE|EXEC}. */ if (0 != (~(NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC) & prot)) { NaClLog(LOG_INFO, "NaClDescImcShmMap: prot has other bits than" " PROT_{READ|WRITE|EXEC}\n"); return -NACL_ABI_EINVAL; } /* * Map from NACL_ABI_ prot and flags bits to IMC library flags, * which will later map back into posix-style prot/flags on *x * boxen, and to MapViewOfFileEx arguments on Windows. */ nacl_imc_prot = 0; if (NACL_ABI_PROT_READ & prot) { nacl_imc_prot |= NACL_PROT_READ; } if (NACL_ABI_PROT_WRITE & prot) { nacl_imc_prot |= NACL_PROT_WRITE; } if (NACL_ABI_PROT_EXEC & prot) { nacl_imc_prot |= NACL_PROT_EXEC; } nacl_imc_flags = NACL_MAP_SHARED; if (0 == (NACL_ABI_MAP_FIXED & flags)) { /* start_addr is a hint, and we just ignore the hint... */ if (!NaClFindAddressSpace(&addr, len)) { NaClLog(1, "NaClDescImcShmMap: no address space?!?\n"); return -NACL_ABI_ENOMEM; } start_addr = (void *) addr; } nacl_imc_flags |= NACL_MAP_FIXED; tmp_off64 = offset + len; /* just NaClRoundAllocPage, but in 64 bits */ tmp_off64 = ((tmp_off64 + NACL_MAP_PAGESIZE - 1) & ~(uint64_t) (NACL_MAP_PAGESIZE - 1)); if (tmp_off64 > INT32_MAX) { NaClLog(LOG_INFO, "NaClDescImcShmMap: total offset exceeds 32-bits\n"); return -NACL_ABI_EOVERFLOW; } /* * For *x, we just map with MAP_FIXED and the kernel takes care of * atomically unmapping any existing memory. For Windows, we must * unmap existing memory first, which creates a race condition, * where some other innocent thread puts some other memory into the * hole, and that memory becomes vulnerable to attack by the * untrusted NaCl application. * * For now, abort the process. We will need to figure out how to * re-architect this code to do the address space move, since it is * deep surgery and we'll need to ensure that all threads have * stopped and any addresses derived from the old address space * would not be on any thread's call stack, i.e., stop the thread in * user space or before entering real service runtime code. This * means that no application thread may be indefinitely blocked * performing a service call in the service runtime, since otherwise * there is no way for us to stop all threads. * * TODO(bsy): We will probably return an internal error code * -NACL_ABI_E_MOVE_ADDRESS_SPACE to ask the caller to do the address space * dance. */ for (addr = (uintptr_t) start_addr, end_addr = addr + len, tmp_off = (off_t) offset; addr < end_addr; addr += NACL_MAP_PAGESIZE, tmp_off += NACL_MAP_PAGESIZE) { /* * Minimize the time between the unmap and the map for the same * page: we interleave the unmap and map for the pages, rather * than do all the unmap first and then do all of the map * operations. */ if (0 != (rv = (*effp->vtbl->UnmapMemory)(effp, addr, NACL_MAP_PAGESIZE))) { NaClLog(LOG_FATAL, ("NaClDescImcShmMap: error %d --" " could not unmap 0x%08"NACL_PRIxPTR", length 0x%x\n"), rv, addr, NACL_MAP_PAGESIZE); } result = NaClMap((void *) addr, NACL_MAP_PAGESIZE, nacl_imc_prot, nacl_imc_flags, self->h, tmp_off); if (NACL_MAP_FAILED == result) { return -NACL_ABI_E_MOVE_ADDRESS_SPACE; } if (0 != (NACL_ABI_MAP_FIXED & flags) && result != (void *) addr) { NaClLog(LOG_FATAL, ("NaClDescImcShmMap: NACL_MAP_FIXED but" " got 0x%08"NACL_PRIxPTR" instead of 0x%08"NACL_PRIxPTR"\n"), (uintptr_t) result, addr); } } return (uintptr_t) start_addr; }
static uintptr_t NaClDescImcShmMap(struct NaClDesc *vself, struct NaClDescEffector *effp, void *start_addr, size_t len, int prot, int flags, nacl_off64_t offset) { struct NaClDescImcShm *self = (struct NaClDescImcShm *) vself; int nacl_imc_prot; int nacl_imc_flags; uintptr_t addr; void *result; nacl_off64_t tmp_off64; /* * shm must have NACL_ABI_MAP_SHARED in flags, and all calls through * this API must supply a start_addr, so NACL_ABI_MAP_FIXED is * assumed. */ if (NACL_ABI_MAP_SHARED != (flags & NACL_ABI_MAP_SHARING_MASK)) { NaClLog(LOG_INFO, ("NaClDescImcShmMap: Mapping not NACL_ABI_MAP_SHARED," " flags 0x%x\n"), flags); return -NACL_ABI_EINVAL; } if (0 != (NACL_ABI_MAP_FIXED & flags) && NULL == start_addr) { NaClLog(LOG_INFO, ("NaClDescImcShmMap: Mapping NACL_ABI_MAP_FIXED" " but start_addr is NULL\n")); } /* post-condition: if NULL == start_addr, then NACL_ABI_MAP_FIXED not set */ /* * prot must not contain bits other than PROT_{READ|WRITE|EXEC}. */ if (0 != (~(NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC) & prot)) { NaClLog(LOG_INFO, "NaClDescImcShmMap: prot has other bits than" " PROT_{READ|WRITE|EXEC}\n"); return -NACL_ABI_EINVAL; } /* * Map from NACL_ABI_ prot and flags bits to IMC library flags, * which will later map back into posix-style prot/flags on *x * boxen, and to MapViewOfFileEx arguments on Windows. */ nacl_imc_prot = 0; if (NACL_ABI_PROT_READ & prot) { nacl_imc_prot |= NACL_PROT_READ; } if (NACL_ABI_PROT_WRITE & prot) { nacl_imc_prot |= NACL_PROT_WRITE; } if (NACL_ABI_PROT_EXEC & prot) { nacl_imc_prot |= NACL_PROT_EXEC; } nacl_imc_flags = NACL_MAP_SHARED; if (0 == (NACL_ABI_MAP_FIXED & flags)) { /* start_addr is a hint, and we just ignore the hint... */ if (!NaClFindAddressSpace(&addr, len)) { NaClLog(1, "NaClDescImcShmMap: no address space?!?\n"); return -NACL_ABI_ENOMEM; } start_addr = (void *) addr; } nacl_imc_flags |= NACL_MAP_FIXED; tmp_off64 = offset + len; /* just NaClRoundAllocPage, but in 64 bits */ tmp_off64 = ((tmp_off64 + NACL_MAP_PAGESIZE - 1) & ~(uint64_t) (NACL_MAP_PAGESIZE - 1)); if (tmp_off64 > INT32_MAX) { NaClLog(LOG_INFO, "NaClDescImcShmMap: total offset exceeds 32-bits\n"); return -NACL_ABI_EOVERFLOW; } result = NaClMap(effp, (void *) start_addr, len, nacl_imc_prot, nacl_imc_flags, self->h, (off_t) offset); if (NACL_MAP_FAILED == result) { return -NACL_ABI_E_MOVE_ADDRESS_SPACE; } if (0 != (NACL_ABI_MAP_FIXED & flags) && result != (void *) start_addr) { NaClLog(LOG_FATAL, ("NaClDescImcShmMap: NACL_MAP_FIXED but got %p instead of %p\n"), result, start_addr); } return (uintptr_t) start_addr; }