int32_t NaClSysGetTimeOfDay(struct NaClAppThread *natp, struct nacl_abi_timeval *tv, struct nacl_abi_timezone *tz) { int32_t retval; uintptr_t sysaddr; UNREFERENCED_PARAMETER(tz); NaClSysCommonThreadSyscallEnter(natp); sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) tv, sizeof tv); /* * tz is not supported in linux, nor is it supported by glibc, since * tzset(3) and the zoneinfo file should be used instead. * * TODO(bsy) Do we make the zoneinfo directory available to * applications? */ if (kNaClBadAddress == sysaddr) { retval = -NACL_ABI_EFAULT; goto cleanup; } retval = NaClGetTimeOfDay((struct nacl_abi_timeval *) sysaddr); cleanup: NaClSysCommonThreadSyscallLeave(natp); return retval; }
/* ARGSUSED */ int32_t NaClSysClock(struct NaClAppThread *natp) { int32_t retval; UNREFERENCED_PARAMETER(natp); NaClSysCommonThreadSyscallEnter(natp); retval = clock(); NaClSysCommonThreadSyscallLeave(natp); return retval; }
int32_t NaClSysGetpid(struct NaClAppThread *natp) { int32_t pid; NaClSysCommonThreadSyscallEnter(natp); pid = getpid(); /* TODO(bsy): obfuscate? */ NaClLog(4, "NaClSysGetpid: returning %d\n", pid); NaClSysCommonThreadSyscallLeave(natp); return pid; }
/* * TODO(bsy): REMOVE THIS AND PROVIDE GETRUSAGE. This is normally * not a syscall; instead, it is a library routine on top of * getrusage, with appropriate clock tick translation. */ int32_t NaClSysClock(struct NaClAppThread *natp) { int32_t retval; NaClLog(3, ("Entered NaClSysClock(%08"NACL_PRIxPTR")\n"), (uintptr_t) natp); NaClSysCommonThreadSyscallEnter(natp); retval = clock(); NaClSysCommonThreadSyscallLeave(natp); return retval; }
int32_t NaClSysSysconf(struct NaClAppThread *natp, int32_t name, int32_t *result) { int32_t retval = -NACL_ABI_EINVAL; static int32_t number_of_workers = -1; uintptr_t sysaddr; NaClLog(3, ("Entered NaClSysSysconf(%08"NACL_PRIxPTR "x, %d, 0x%08"NACL_PRIxPTR")\n"), (uintptr_t) natp, name, (uintptr_t) result); NaClSysCommonThreadSyscallEnter(natp); sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) result, sizeof(*result)); if (kNaClBadAddress == sysaddr) { retval = -NACL_ABI_EINVAL; goto cleanup; } switch (name) { #ifdef _SC_NPROCESSORS_ONLN case NACL_ABI__SC_NPROCESSORS_ONLN: { if (-1 == number_of_workers) { number_of_workers = sysconf(_SC_NPROCESSORS_ONLN); } if (-1 == number_of_workers) { /* failed to get the number of processors */ retval = -NACL_ABI_EINVAL; goto cleanup; } *(int32_t*)sysaddr = number_of_workers; break; } #endif case NACL_ABI__SC_SENDMSG_MAX_SIZE: { /* TODO(sehr,bsy): this value needs to be determined at run time. */ const int32_t kImcSendMsgMaxSize = 1 << 16; *(int32_t*)sysaddr = kImcSendMsgMaxSize; break; } default: retval = -NACL_ABI_EINVAL; goto cleanup; } retval = 0; cleanup: NaClSysCommonThreadSyscallLeave(natp); return retval; }
int32_t NaClSysGetTimeOfDay(struct NaClAppThread *natp, struct nacl_abi_timeval *tv, struct nacl_abi_timezone *tz) { uintptr_t sysaddr; int retval; struct nacl_abi_timeval now; UNREFERENCED_PARAMETER(tz); NaClLog(3, ("Entered NaClSysGetTimeOfDay(%08"NACL_PRIxPTR ", 0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR")\n"), (uintptr_t) natp, (uintptr_t) tv, (uintptr_t) tz); NaClSysCommonThreadSyscallEnter(natp); sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) tv, sizeof tv); /* * tz is not supported in linux, nor is it supported by glibc, since * tzset(3) and the zoneinfo file should be used instead. * * TODO(bsy) Do we make the zoneinfo directory available to * applications? */ if (kNaClBadAddress == sysaddr) { retval = -NACL_ABI_EFAULT; goto cleanup; } retval = NaClGetTimeOfDay(&now); if (0 == retval) { /* * To make it harder to distinguish Linux platforms from Windows, * coarsen the time to the same level we get on Windows - * milliseconds, unless in "debug" mode. */ if (!NaClHighResolutionTimerEnabled()) { now.nacl_abi_tv_usec = (now.nacl_abi_tv_usec / 1000) * 1000; } CHECK(now.nacl_abi_tv_usec >= 0); CHECK(now.nacl_abi_tv_usec < NACL_MICROS_PER_UNIT); *(struct nacl_abi_timeval *) sysaddr = now; } cleanup: NaClSysCommonThreadSyscallLeave(natp); return retval; }
int32_t NaClSysNanosleep(struct NaClAppThread *natp, struct nacl_abi_timespec *req, struct nacl_abi_timespec *rem) { uintptr_t sys_req; int retval = -NACL_ABI_EINVAL; struct nacl_abi_timespec host_req; UNREFERENCED_PARAMETER(rem); NaClLog(4, "NaClSysNanosleep(%08x)\n", (uintptr_t) req); NaClSysCommonThreadSyscallEnter(natp); sys_req = NaClUserToSysAddrRange(natp->nap, (uintptr_t) req, sizeof *req); if (kNaClBadAddress == sys_req) { retval = -NACL_ABI_EFAULT; goto cleanup; } /* copy once */ host_req = *(struct nacl_abi_timespec *) sys_req; /* * We assume that we do not need to normalize the time request values. * * If bogus values can cause the underlying OS to get into trouble, * then we need more checking here. */ NaClLog(4, "NaClSysNanosleep(time = %d.%09ld S)\n", host_req.tv_sec, host_req.tv_nsec); retval = NaClNanosleep(&host_req, NULL); cleanup: NaClSysCommonThreadSyscallLeave(natp); return retval; }
int32_t NaClSysSysconf(struct NaClAppThread *natp, int32_t name, int32_t *result) { int32_t retval = -NACL_ABI_EINVAL; static int32_t number_of_workers = 0; uintptr_t sysaddr; NaClSysCommonThreadSyscallEnter(natp); sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) result, sizeof(*result)); if (kNaClBadAddress == sysaddr) { retval = -NACL_ABI_EINVAL; goto cleanup; } switch (name) { case NACL_ABI__SC_NPROCESSORS_ONLN: { if (0 == number_of_workers) { SYSTEM_INFO si; GetSystemInfo(&si); number_of_workers = (int32_t)si.dwNumberOfProcessors; } *(int32_t*)sysaddr = number_of_workers; break; } default: retval = -NACL_ABI_EINVAL; goto cleanup; } retval = 0; cleanup: NaClSysCommonThreadSyscallLeave(natp); return retval; }
int32_t NaClSysNanosleep(struct NaClAppThread *natp, struct nacl_abi_timespec *req, struct nacl_abi_timespec *rem) { uintptr_t sys_req; uintptr_t sys_rem; struct nacl_abi_timespec t_sleep; struct nacl_abi_timespec t_rem; struct nacl_abi_timespec *remptr; int retval = -NACL_ABI_EINVAL; NaClLog(3, ("Entered NaClSysNanosleep(0x%08"NACL_PRIxPTR ", 0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR"x)\n"), (uintptr_t) natp, (uintptr_t) req, (uintptr_t) rem); NaClSysCommonThreadSyscallEnter(natp); sys_req = NaClUserToSysAddrRange(natp->nap, (uintptr_t) req, sizeof *req); if (kNaClBadAddress == sys_req) { retval = -NACL_ABI_EFAULT; goto cleanup; } if (NULL == rem) { sys_rem = 0; } else { sys_rem = NaClUserToSysAddrRange(natp->nap, (uintptr_t) rem, sizeof *rem); if (kNaClBadAddress == sys_rem) { retval = -NACL_ABI_EFAULT; goto cleanup; } } /* * post-condition: if sys_rem is non-NULL, it's safe to write to * (modulo thread races) and the user code wants the remaining time * written there. */ NaClLog(4, " copying timespec from %08"NACL_PRIxPTR"x\n", sys_req); /* copy once */ t_sleep = *(struct nacl_abi_timespec *) sys_req; remptr = (0 == sys_rem) ? NULL : &t_rem; /* NULL != remptr \equiv NULL != rem */ /* * We assume that we do not need to normalize the time request values. * * If bogus values can cause the underlying OS to get into trouble, * then we need more checking here. */ NaClLog(4, "NaClSysNanosleep(time = %"NACL_PRId64".%09"NACL_PRId64" S)\n", (int64_t) t_sleep.tv_sec, (int64_t) t_sleep.tv_nsec); retval = NaClNanosleep(&t_sleep, remptr); NaClLog(4, "NaClNanosleep returned %d\n", retval); if (-EINTR == retval && NULL != rem) { /* definitely different types, and shape may actually differ too. */ rem = (struct nacl_abi_timespec *) sys_rem; rem->tv_sec = remptr->tv_sec; rem->tv_nsec = remptr->tv_nsec; } cleanup: NaClLog(4, "nanosleep done.\n"); NaClSysCommonThreadSyscallLeave(natp); return retval; }
int32_t NaClSysMunmap(struct NaClAppThread *natp, void *start, size_t length) { int32_t retval = -NACL_ABI_EINVAL; uintptr_t sysaddr; int holding_app_lock = 0; size_t alloc_rounded_length; NaClLog(3, "Entered NaClSysMunmap(0x%08"NACL_PRIxPTR", " "0x%08"NACL_PRIxPTR", 0x%"NACL_PRIxS")\n", (uintptr_t) natp, (uintptr_t) start, length); NaClSysCommonThreadSyscallEnter(natp); if (!NaClIsAllocPageMultiple((uintptr_t) start)) { NaClLog(4, "start addr not allocation multiple\n"); retval = -NACL_ABI_EINVAL; goto cleanup; } if (0 == length) { /* * linux mmap of zero length yields a failure, but osx does not, leading * to a NaClVmmapUpdate of zero pages, which should not occur. */ retval = -NACL_ABI_EINVAL; goto cleanup; } alloc_rounded_length = NaClRoundAllocPage(length); if (alloc_rounded_length != length) { length = alloc_rounded_length; NaClLog(LOG_WARNING, "munmap: rounded length to 0x%"NACL_PRIxS"\n", length); } sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) start, length); if (kNaClBadAddress == sysaddr) { NaClLog(4, "region not user addresses\n"); retval = -NACL_ABI_EFAULT; goto cleanup; } NaClXMutexLock(&natp->nap->mu); while (0 != natp->nap->threads_launching) { NaClXCondVarWait(&natp->nap->cv, &natp->nap->mu); } natp->nap->vm_hole_may_exist = 1; holding_app_lock = 1; /* * NB: windows (or generic) version would use Munmap virtual * function from the backing NaClDesc object obtained by iterating * through the address map for the region, and those Munmap virtual * functions may return -NACL_ABI_E_MOVE_ADDRESS_SPACE. * * We should hold the application lock while doing this iteration * and unmapping, so that the address space is consistent for other * threads. */ /* * User should be unable to unmap any executable pages. We check here. */ if (NaClSysCommonAddrRangeContainsExecutablePages_mu(natp->nap, (uintptr_t) start, length)) { NaClLog(2, "NaClSysMunmap: region contains executable pages\n"); retval = -NACL_ABI_EINVAL; goto cleanup; } /* * Overwrite current mapping with inaccessible, anonymous * zero-filled pages, which should be copy-on-write and thus * relatively cheap. Do not open up an address space hole. */ NaClLog(4, ("NaClSysMunmap: mmap(0x%08"NACL_PRIxPTR", 0x%"NACL_PRIxS"," " 0x%x, 0x%x, -1, 0)\n"), sysaddr, length, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED); if (MAP_FAILED == mmap((void *) sysaddr, length, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, (off_t) 0)) { NaClLog(4, "mmap to put in anonymous memory failed, errno = %d\n", errno); retval = -NaClXlateErrno(errno); goto cleanup; } NaClVmmapUpdate(&natp->nap->mem_map, (NaClSysToUser(natp->nap, (uintptr_t) sysaddr) >> NACL_PAGESHIFT), length >> NACL_PAGESHIFT, 0, /* prot */ (struct NaClMemObj *) NULL, 1); /* Delete mapping */ retval = 0; cleanup: if (holding_app_lock) { natp->nap->vm_hole_may_exist = 0; NaClXCondVarBroadcast(&natp->nap->cv); NaClXMutexUnlock(&natp->nap->mu); } NaClSysCommonThreadSyscallLeave(natp); return retval; }
int32_t NaClSysMunmap(struct NaClAppThread *natp, void *start, size_t length) { int32_t retval = -NACL_ABI_EINVAL; uintptr_t sysaddr; uintptr_t addr; uintptr_t endaddr; int holding_app_lock = 0; size_t alloc_rounded_length; NaClLog(3, "NaClSysMunmap(0x%08x, 0x%08x, 0x%x)\n", natp, start, length); NaClSysCommonThreadSyscallEnter(natp); if (!NaClIsAllocPageMultiple((uintptr_t) start)) { NaClLog(4, "start addr not allocation multiple\n"); retval = -NACL_ABI_EINVAL; goto cleanup; } if (0 == length) { /* * linux mmap of zero length yields a failure, but windows code * would just iterate through and do nothing, so does not yield a * failure. */ retval = -NACL_ABI_EINVAL; goto cleanup; } alloc_rounded_length = NaClRoundAllocPage(length); if (alloc_rounded_length != length) { length = alloc_rounded_length; NaClLog(LOG_WARNING, "munmap: rounded length to 0x%x\n", length); } sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) start, length); if (kNaClBadAddress == sysaddr) { retval = -NACL_ABI_EFAULT; goto cleanup; } NaClXMutexLock(&natp->nap->mu); holding_app_lock = 1; /* * User should be unable to unmap any executable pages. We check here. */ if (NaClSysCommonAddrRangeContainsExecutablePages_mu(natp->nap, (uintptr_t) start, length)) { NaClLog(2, "NaClSysMunmap: region contains executable pages\n"); retval = -NACL_ABI_EINVAL; goto cleanup; } endaddr = sysaddr + length; for (addr = sysaddr; addr < endaddr; addr += NACL_MAP_PAGESIZE) { struct NaClVmmapEntry const *entry; entry = NaClVmmapFindPage(&natp->nap->mem_map, NaClSysToUser(natp->nap, addr) >> NACL_PAGESHIFT); if (NULL == entry) { NaClLog(LOG_FATAL, "NaClSysMunmap: could not find VM map entry for addr 0x%08x\n", addr); } NaClLog(3, ("NaClSysMunmap: addr 0x%08x, nmop 0x%08x\n"), addr, entry->nmop); if (NULL == entry->nmop) { /* anonymous memory; we just decommit it and thus make it inaccessible */ if (!VirtualFree((void *) addr, NACL_MAP_PAGESIZE, MEM_DECOMMIT)) { int error = GetLastError(); NaClLog(LOG_FATAL, ("NaClSysMunmap: Could not VirtualFree MEM_DECOMMIT" " addr 0x%08x, error %d (0x%x)\n"), addr, error, error); } } else { /* * This should invoke a "safe" version of unmap that fills the * memory hole as quickly as possible, and may return * -NACL_ABI_E_MOVE_ADDRESS_SPACE. The "safe" version just * minimizes the size of the timing hole for any racers, plus * the size of the memory window is only 64KB, rather than * whatever size the user is unmapping. */ retval = (*entry->nmop->ndp->vtbl->Unmap)(entry->nmop->ndp, natp->effp, (void*) addr, NACL_MAP_PAGESIZE); if (0 != retval) { NaClLog(LOG_FATAL, ("NaClSysMunmap: Could not unmap via ndp->Unmap 0x%08x" " and cannot handle address space move\n"), addr); } } NaClVmmapUpdate(&natp->nap->mem_map, (NaClSysToUser(natp->nap, (uintptr_t) addr) >> NACL_PAGESHIFT), NACL_PAGES_PER_MAP, 0, /* prot */ (struct NaClMemObj *) NULL, 1); /* delete */ } retval = 0; cleanup: if (holding_app_lock) { NaClXMutexUnlock(&natp->nap->mu); } NaClSysCommonThreadSyscallLeave(natp); return retval; }