/* * NaClAllocatePow2AlignedMemory is for allocating a large amount of * memory of mem_sz bytes that must be address aligned, so that * log_alignment low-order address bits must be zero. * * Returns the aligned region on success, or NULL on failure. */ static void *NaClAllocatePow2AlignedMemory(size_t mem_sz, size_t log_alignment) { uintptr_t pow2align; size_t request_sz; void *mem_ptr; uintptr_t orig_addr; uintptr_t rounded_addr; size_t extra; pow2align = ((uintptr_t)1) << log_alignment; request_sz = mem_sz + pow2align; ZLOGS(LOG_INSANE, "%25s %016lx", " Ask:", request_sz); /* d'b: try to get the fixed address r15 (user base register) */ /* * WARNING: mmap can overwrite the zerovm dynamically linked code. * to prevent it the code should be linked statically */ mem_ptr = mmap(R15_CONST, request_sz, PROT_NONE, ABSOLUTE_MMAP, -1, (off_t)0); if(MAP_FAILED == mem_ptr) { ZLOG(LOG_ERROR, "the base register absolute address allocation failed!" " trying to allocate user space in NOT DETERMINISTIC WAY"); mem_ptr = mmap(NULL, request_sz, PROT_NONE, RELATIVE_MMAP, -1, (off_t)0); ZLOGFAIL(MAP_FAILED == mem_ptr, ENOMEM, FAILED_MSG); } orig_addr = (uintptr_t)mem_ptr; ZLOGS(LOG_INSANE, "%25s %016lx", "orig memory at", orig_addr); rounded_addr = (orig_addr + (pow2align - 1)) & ~(pow2align - 1); extra = rounded_addr - orig_addr; if(0 != extra) { ZLOGS(LOG_INSANE, "%25s %016lx, %016lx", "Freeing front:", orig_addr, extra); ZLOGFAIL(-1 == munmap((void *)orig_addr, extra), errno, "munmap front failed"); } extra = pow2align - extra; if(0 != extra) { ZLOGS(LOG_INSANE, "%25s %016lx, %016lx", "Freeing tail:", rounded_addr + mem_sz, extra); ZLOGFAIL(-1 == munmap((void *)(rounded_addr + mem_sz), extra), errno, "munmap tail failed"); } ZLOGS(LOG_INSANE, "%25s %016lx", "Aligned memory:", rounded_addr); /* * we could also mmap again at rounded_addr w/o MAP_NORESERVE etc to * ensure that we have the memory, but that's better done in another * utility function. the semantics here is no paging space * reserved, as in Windows MEM_RESERVE without MEM_COMMIT. */ return (void *)rounded_addr; }
/* * read specified amount of bytes from given desc/offset to buffer * return amount of read bytes or negative error code if call failed */ static int32_t ZVMReadHandle(struct NaClApp *nap, int ch, char *buffer, int32_t size, int64_t offset) { struct ChannelDesc *channel; int64_t tail; char *sys_buffer; assert(nap != NULL); assert(nap->manifest != NULL); assert(nap->manifest->channels != NULL); /* check the channel number */ if(ch < 0 || ch >= nap->manifest->channels->len) { ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=%p, size=%d, offset=%ld", ch, buffer, size, offset); return -EINVAL; } channel = CH_CH(nap->manifest, ch); ZLOGS(LOG_INSANE, "channel %s, buffer=%p, size=%d, offset=%ld", channel->alias, buffer, size, offset); /* check buffer and convert address */ if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_WRITE) == -1) return -EINVAL; sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t)buffer); /* ignore user offset for sequential access read */ if(CH_SEQ_READABLE(channel)) offset = channel->getpos; else /* prevent reading beyond the end of the random access channels */ size = MIN(channel->size - offset, size); /* check arguments sanity */ if(size == 0) return 0; /* success. user has read 0 bytes */ if(size < 0) return -EFAULT; if(offset < 0) return -EINVAL; /* check for eof */ if(channel->eof) return 0; /* check limits */ if(channel->counters[GetsLimit] >= channel->limits[GetsLimit]) return -EDQUOT; if(CH_RND_READABLE(channel)) if(offset >= channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit] + channel->size) return -EINVAL; /* calculate i/o leftovers */ tail = channel->limits[GetSizeLimit] - channel->counters[GetSizeLimit]; if(size > tail) size = tail; if(size < 1) return -EDQUOT; /* read data */ return ChannelRead(channel, sys_buffer, (size_t)size, (off_t)offset); }
int32_t TrapHandler(struct NaClApp *nap, uint32_t args) { uint64_t *sargs; int retcode = 0; int i; assert(nap != NULL); assert(nap->manifest != NULL); /* * translate address from user space to system * note: cannot set "trap error" */ sargs = (uint64_t*)NaClUserToSys(nap, (uintptr_t)args); i = FunctionIndexById(*sargs); ZLOGS(LOG_DEBUG, "%s called", function[i]); ZTrace("untrusted code"); switch(*sargs) { case TrapFork: if(Daemon(nap) == 0) { SyscallZTrace(5, function[5]); ZVMExitHandle(nap, 0); } break; case TrapExit: ZVMExitHandle(nap, (int32_t)sargs[2]); break; case TrapRead: retcode = ZVMReadHandle(nap, (int)sargs[2], (char*)sargs[3], (int32_t)sargs[4], sargs[5]); break; case TrapWrite: retcode = ZVMWriteHandle(nap, (int)sargs[2], (char*)sargs[3], (int32_t)sargs[4], sargs[5]); break; case TrapJail: retcode = ZVMJailHandle(nap, (uint32_t)sargs[2], (int32_t)sargs[3]); break; case TrapUnjail: retcode = ZVMUnjailHandle(nap, (uint32_t)sargs[2], (int32_t)sargs[3]); break; default: retcode = -EPERM; ZLOG(LOG_ERROR, "function %ld is not supported", *sargs); break; } /* report, ztrace and return */ FastReport(); ZLOGS(LOG_DEBUG, "%s returned %d", function[i], retcode); SyscallZTrace(i, function[i], sargs[2], sargs[3], sargs[4], sargs[5], retcode); return retcode; }
void ElfImageLoad(const struct ElfImage *image, struct Gio *gp, uint8_t addr_bits, uintptr_t mem_start) { int segnum; uintptr_t paddr; uintptr_t end_vaddr; for(segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) { const Elf_Phdr *php = &image->phdrs[segnum]; /* did we decide that we will load this segment earlier? */ if(!image->loadable[segnum]) continue; ZLOGS(LOG_INSANE, "loading segment %d", segnum); if(0 == php->p_filesz) { ZLOGS(LOG_INSANE, "zero-sized segment. ignoring..."); continue; } end_vaddr = php->p_vaddr + php->p_filesz; /* integer overflow? */ ZLOGFAIL(end_vaddr < php->p_vaddr, EFAULT, "parameter error should have been detected already"); /* * is the end virtual address within the NaCl application's * address space? if it is, it implies that the start virtual * address is also. */ ZLOGFAIL(end_vaddr >= ((uintptr_t)1U << addr_bits), EFAULT, "parameter error should have been detected already"); paddr = mem_start + php->p_vaddr; ZLOGS(LOG_INSANE, "Seek to position %d (0x%x)", php->p_offset, php->p_offset); /* * NB: php->p_offset may not be a valid off_t on 64-bit systems, but * in that case Seek() will error out. * d'b: fail if ELF executable segment header parameter error */ ZLOGFAIL((*gp->vtbl->Seek)(gp, (off_t)php->p_offset, SEEK_SET) == (off_t)-1, ENOEXEC, "seek failure segment %d", segnum); ZLOGS(LOG_INSANE, "Reading %d (0x%x) bytes to address 0x%x", php->p_filesz, php->p_filesz, paddr); ZLOGFAIL((Elf_Word)(*gp->vtbl->Read)(gp, (void *)paddr, php->p_filesz) != php->p_filesz, ENOEXEC, "load failure segment %d", segnum); /* region from p_filesz to p_memsz should already be zero filled */ } }
/* log user memory map */ static void LogMemMap(struct NaClApp *nap, int verbosity) { int i; ZLOGS(verbosity, "user memory map (in pages):"); for(i = 0; i < MemMapSize; ++i) ZLOGS(verbosity, "%s: address = 0x%08x, size = 0x%08x, protection = x", nap->mem_map[i].name, (uint32_t) nap->mem_map[i].start, (uint32_t) nap->mem_map[i].size, nap->mem_map[i].prot); }
/* * "One Ring" syscall main routine. the nacl syscalls replacement. * "args" is an array of syscall name and its arguments * note: since nacl patch two 1st arguments if they are pointers, arg[1] are not used * todo(d'b): check how nacl decide to patch arguments. */ int32_t TrapHandler(struct NaClApp *nap, uint32_t args) { uint64_t *sys_args; int retcode = 0; assert(nap != NULL); assert(nap->system_manifest != NULL); /* * translate address from user space to system * note: cannot set "trap error" */ sys_args = (uint64_t*)NaClUserToSys(nap, (uintptr_t) args); ZLOGS(LOG_DEBUG, "%s called", FunctionNameById(sys_args[0])); switch(*sys_args) { case TrapExit: retcode = ZVMExitHandle(nap, (int32_t) sys_args[2]); break; case TrapRead: retcode = ZVMReadHandle(nap, (int)sys_args[2], (char*)sys_args[3], (int32_t)sys_args[4], sys_args[5]); break; case TrapWrite: retcode = ZVMWriteHandle(nap, (int)sys_args[2], (char*)sys_args[3], (int32_t)sys_args[4], sys_args[5]); break; case TrapSyscallback: retcode = ZVMSyscallback(nap, (int32_t)sys_args[2]); break; case TrapChannels: retcode = ZVMChannels(nap, (struct ZVMChannel*)sys_args[2]); break; case TrapChannelName: retcode = ZVMChannelName(nap, (struct ZVMChannel*)sys_args[2], (int32_t)sys_args[3]); break; case TrapHeapEnd: retcode = ZVMHeapEnd(nap); break; case TrapHeapPtr: retcode = ZVMHeapPtr(nap); break; default: retcode = -EPERM; ZLOG(LOG_ERROR, "function %ld is not supported", *sys_args); break; } ZLOGS(LOG_DEBUG, "%s returned %d", FunctionNameById(sys_args[0]), retcode); return retcode; }
void NaClAllocAddrSpace(struct NaClApp *nap) { void *mem; uintptr_t hole_start; size_t hole_size; uintptr_t stack_start; ZLOGS(LOG_DEBUG, "calling NaClAllocateSpace(*,0x%016x)", ((size_t)1 << nap->addr_bits)); NaClAllocateSpace(&mem, (uintptr_t) 1U << nap->addr_bits); nap->mem_start = (uintptr_t) mem; ZLOGS(LOG_DEBUG, "allocated memory at 0x%08x", nap->mem_start); hole_start = NaClRoundAllocPage(nap->data_end); ZLOGFAIL(nap->stack_size >= ((uintptr_t) 1U) << nap->addr_bits, EFAULT, "NaClAllocAddrSpace: stack too large!"); stack_start = (((uintptr_t) 1U) << nap->addr_bits) - nap->stack_size; stack_start = NaClTruncAllocPage(stack_start); ZLOGFAIL(stack_start < hole_start, EFAULT, "Memory 'hole' between end of BSS and start of stack is negative in size"); hole_size = stack_start - hole_start; hole_size = NaClTruncAllocPage(hole_size); /* * mprotect and madvise unused data space to "free" it up, but * retain mapping so no other memory can be mapped into those * addresses. */ if(hole_size != 0) { ZLOGS(LOG_DEBUG, "madvising 0x%08x, 0x%08x, MADV_DONTNEED", nap->mem_start + hole_start, hole_size); ZLOGFAIL(0 != NaCl_madvise((void*)(nap->mem_start + hole_start), hole_size, MADV_DONTNEED), errno, "madvise failed. cannot release unused data segment"); ZLOGS(LOG_DEBUG, "mprotecting 0x%08x, 0x%08x, PROT_NONE", nap->mem_start + hole_start, hole_size); ZLOGFAIL(0 != NaCl_mprotect((void *)(nap->mem_start + hole_start), hole_size, PROT_NONE), errno, "mprotect failed. cannot protect pages"); } else ZLOGS(LOG_DEBUG, "there is no hole between end of data and the beginning of stack"); }
/* * write specified amount of bytes from buffer to given desc/offset * return amount of read bytes or negative error code if call failed */ static int32_t ZVMWriteHandle(struct NaClApp *nap, int ch, const char *buffer, int32_t size, int64_t offset) { struct ChannelDesc *channel; int64_t tail; const char *sys_buffer; assert(nap != NULL); assert(nap->manifest != NULL); assert(nap->manifest->channels != NULL); /* check the channel number */ if(ch < 0 || ch >= nap->manifest->channels->len) { ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=%p, size=%d, offset=%ld", ch, buffer, size, offset); return -EINVAL; } channel = CH_CH(nap->manifest, ch); ZLOGS(LOG_INSANE, "channel %s, buffer=%p, size=%d, offset=%ld", channel->alias, buffer, size, offset); /* check buffer and convert address */ if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_READ) == -1) return -EINVAL; sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t) buffer); /* ignore user offset for sequential access write */ if(CH_SEQ_WRITEABLE(channel)) offset = channel->putpos; /* check arguments sanity */ if(size == 0) return 0; /* success. user has read 0 bytes */ if(size < 0) return -EFAULT; if(offset < 0) return -EINVAL; /* check limits */ if(channel->counters[PutsLimit] >= channel->limits[PutsLimit]) return -EDQUOT; tail = channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit]; if(offset >= channel->limits[PutSizeLimit] && !((CH_RW_TYPE(channel) & 1) == 1)) return -EINVAL; if(offset >= channel->size + tail) return -EINVAL; if(size > tail) size = tail; if(size < 1) return -EDQUOT; /* write data */ return ChannelWrite(channel, sys_buffer, (size_t)size, (off_t)offset); }
NORETURN void CreateSession(struct NaClApp *nap) { uintptr_t stack_ptr; assert(nap != NULL); /* set up user stack */ stack_ptr = nap->mem_start + ((uintptr_t)1U << nap->addr_bits); stack_ptr -= STACK_USER_DATA_SIZE; memset((void*)stack_ptr, 0, STACK_USER_DATA_SIZE); ((uint32_t*)stack_ptr)[4] = 1; ((uint32_t*)stack_ptr)[5] = 0xfffffff0; /* construct "nacl_user" global */ ThreadContextCtor(nacl_user, nap, nap->initial_entry_pt, stack_ptr, 0); nacl_user->sysret = nap->break_addr; nacl_user->prog_ctr = NaClUserToSys(nap, nap->initial_entry_pt); nacl_user->new_prog_ctr = NaClUserToSys(nap, nap->initial_entry_pt); /* initialize "nacl_sys" global */ nacl_sys->rbp = GetStackPtr(); nacl_sys->rsp = GetStackPtr(); /* pass control to the user side */ ZLOGS(LOG_DEBUG, "SESSION %d STARTED", nap->manifest->node); SwitchToApp(nap, nacl_user->new_prog_ctr); ZLOGFAIL(1, EFAULT, "the unreachable has been reached"); }
/* part of report class dtor */ static void Report(struct NaClApp *nap) { GString *report = g_string_sized_new(BIG_ENOUGH_STRING); char *eol = hide_report ? "; " : "\n"; /* report validator state and user return code */ g_string_append_printf(report, "%s%d%s", REPORT_VALIDATOR, validation_state, eol); g_string_append_printf(report, "%s%d%s", REPORT_RETCODE, user_code, eol); /* add memory digest to cumulative digests if asked */ if(nap != NULL && nap->manifest != NULL) if(nap->manifest->mem_tag != NULL) ReportTag(STDRAM, GetMemoryDigest(nap)); /* report tags digests and remove ending " " if exist */ g_string_append_printf(report, "%s", REPORT_ETAG); g_string_append_printf(report, "%s", digests->len == 0 ? TAG_ENGINE_DISABLED : digests->str); g_string_truncate(report, report->len - 1); /* report accounting and session message */ g_string_append_printf(report, "%s%s%s%s", eol, REPORT_ACCOUNTING, GetAccountingInfo(), eol); g_string_append_printf(report, "%s%s%s", REPORT_STATE, zvm_state, eol); /* output report */ if(hide_report) ZLOGS(LOG_ERROR, "%s", report->str); else ZLOGIF(write(STDOUT_FILENO, report->str, report->len) != report->len, "report write error %d: %s", errno, strerror(errno)); g_string_free(report, TRUE); g_string_free(digests, TRUE); }
NORETURN void CreateSession(struct NaClApp *nap) { uintptr_t stack_ptr; assert(nap != NULL); /* set up user stack */ stack_ptr = nap->mem_start + ((uintptr_t)1U << nap->addr_bits); stack_ptr -= STACK_USER_DATA_SIZE; memset((void*)stack_ptr, 0, STACK_USER_DATA_SIZE); ((uint32_t*)stack_ptr)[4] = 1; ((uint32_t*)stack_ptr)[5] = 0xfffffff0; /* * construct "nacl_user" and "nacl_sys" globals * note: nacl_sys->prog_ctr meaningless but should not be 0 */ ThreadContextCtor(nacl_user, nap, nap->initial_entry_pt, stack_ptr); ThreadContextCtor(nacl_sys, nap, 1, GetStackPtr()); /* pass control to the user side */ ZLOGS(LOG_DEBUG, "SESSION %d STARTED", nap->manifest->node); ContextSwitch(nacl_user); ZLOGFAIL(1, EFAULT, "the unreachable has been reached"); }
int PreloadChannelDtor(struct ChannelDesc *channel, int n) { int code = 0; int handle; assert(channel != NULL); assert(n < channel->source->len); /* adjust the size of writable channels */ handle = GPOINTER_TO_INT(CH_HANDLE(channel, n)); if(channel->limits[PutSizeLimit] && channel->limits[PutsLimit] && CH_PROTO(channel, n) == ProtoRegular) code = ftruncate(handle, channel->size); ZLOGS(LOG_DEBUG, "%s closed with getsize = %ld, putsize = %ld", channel->alias, channel->counters[GetSizeLimit], channel->counters[PutSizeLimit]); if(handle != 0) { if(CH_PROTO(channel, n) == ProtoRegular) close(handle); else fclose(CH_HANDLE(channel, n)); } g_ptr_array_remove(channel->source, CH_FILE(channel, n)); return -(code != 0); }
void PreloadChannelCtor(struct ChannelDesc *channel, int n) { assert(channel != NULL); assert(n < channel->source->len); /* check the given channel */ ZLOGS(LOG_DEBUG, "mounting file %s to alias %s", CH_NAME(channel, n), channel->alias); SetChannelSource(channel, n); switch(CH_PROTO(channel, n)) { case ProtoRegular: RegularChannel(channel, n); break; case ProtoCharacter: case ProtoFIFO: CharacterChannel(channel, n); break; default: ZLOGFAIL(1, EPROTONOSUPPORT, "invalid %s source type %d", channel->alias, channel->type); break; } }
void ReportDtor(int zvm_ret) { SetExitCode(zvm_ret); /* * patch to show special messages instead of signals 24, 25 * and do not calculate etag if session failed */ if(zvm_code != 0) { SpecSignals(); ZLOGS(LOG_ERROR, "SESSION %d FAILED WITH ERROR %d: %s", gnap->manifest == NULL ? 0 : gnap->manifest->node, zvm_code, strerror(zvm_code)); } if(zvm_code != 0) FinalDump(gnap); AccountingDtor(gnap); ChannelsDtor(gnap->manifest); Report(gnap); NaClAppDtor(gnap); /* free user space and globals */ ManifestDtor(gnap->manifest); /* dispose manifest and channels */ FreeDispatchThunk(); ZLogDtor(); _exit(zvm_code); }
/* sets node_id in nap object and user argv[0] */ static void SetNodeName(struct NaClApp *nap) { int i; char *buf[BIG_ENOUGH_SPACE], **tokens = buf; char *pgm_name = GetValueByKey(MFT_NODE); assert(nap != NULL); assert(nap->system_manifest != NULL); assert(nap->system_manifest->cmd_line != NULL); assert(nap->system_manifest->cmd_line_size > 0); /* set the node name (0st parameter) and node id (n/a for the user) */ if(pgm_name == NULL) { nap->system_manifest->cmd_line[0] = NEXE_PGM_NAME; nap->system_manifest->node_id = 0; } else { i = ParseValue(pgm_name, ",", tokens, BIG_ENOUGH_SPACE); ZLOGFAIL(i != 2, EFAULT, "invalid NodeName specified"); ZLOGFAIL(tokens[0] == NULL, EFAULT, "invalid node name"); ZLOGFAIL(tokens[1] == NULL, EFAULT, "invalid node id"); nap->system_manifest->cmd_line[0] = tokens[0]; nap->system_manifest->node_id = ATOI(tokens[1]); ZLOGFAIL(nap->system_manifest->node_id == 0, EFAULT, "node id must be > 0"); } /* put node name and id to the log */ ZLOGS(LOG_DEBUG, "node name = %s, node id = %d", nap->system_manifest->cmd_line[0], nap->system_manifest->node_id); }
/* TODO(d'b): rework "-t" and update the function */ static void OutputReport(char *r) { char *p = NULL; int size = strlen(r); #define REPORT(p) ZLOGIF(write(report_handle, p, size) != size, \ "report write error %d: %s", errno, strerror(errno)) switch(report_mode) { case 3: /* unix socket */ p = g_strdup_printf("0x%06x%s", size, r); size = strlen(p); REPORT(p); g_free(p); break; case 0: /* stdout */ REPORT(r); break; case 1: /* syslog */ ZLOGS(LOG_ERROR, "%s", r); break; default: ZLOG(LOG_ERROR, "invalid report mode %d", report_mode); break; } #undef REPORT }
/* * Fill from static_text_end to end of that page with halt * instruction, which is at least NACL_HALT_LEN in size when no * dynamic text is present. Does not touch dynamic text region, which * should be pre-filled with HLTs. * * By adding NACL_HALT_SLED_SIZE, we ensure that the code region ends * with HLTs, just in case the CPU has a bug in which it fails to * check for running off the end of the x86 code segment. */ void static FillEndOfTextRegion(struct NaClApp *nap) { size_t page_pad; /* * NOTE: make sure we are not silently overwriting data. It is the * toolchain's responsibility to ensure that a NACL_HALT_SLED_SIZE * gap exists. */ ZLOGFAIL(0 != nap->data_start && nap->static_text_end + NACL_HALT_SLED_SIZE > nap->data_start, EFAULT, "Missing gap between text and data for halt_sled"); ZLOGFAIL(0 != nap->rodata_start && nap->static_text_end + NACL_HALT_SLED_SIZE > nap->rodata_start, EFAULT, "Missing gap between text and rodata for halt_sled"); /* No dynamic text exists. Space for NACL_HALT_SLED_SIZE must exist */ page_pad = ROUNDUP_64K(nap->static_text_end + NACL_HALT_SLED_SIZE) - nap->static_text_end; ZLOGFAIL(page_pad < NACL_HALT_SLED_SIZE, EFAULT, FAILED_MSG); ZLOGFAIL(page_pad >= NACL_MAP_PAGESIZE + NACL_HALT_SLED_SIZE, EFAULT, FAILED_MSG); ZLOGS(LOG_INSANE, "Filling with halts: %08lx, %08lx bytes", nap->mem_start + nap->static_text_end, page_pad); FillMemoryRegionWithHalt((void*)(nap->mem_start + nap->static_text_end), page_pad); nap->static_text_end += page_pad; }
void NaClLoadTrampoline(struct NaClApp *nap) { int num_syscalls; int i; uintptr_t addr; ZLOGFAIL(!NaClMakeDispatchThunk(nap), EFAULT, FAILED_MSG); NaClFillTrampolineRegion(nap); /* * Do not bother to fill in the contents of page 0, since we make it * inaccessible later (see sel_addrspace.c, NaClMemoryProtection) * anyway to help detect NULL pointer errors, and we might as well * not dirty the page. * * The last syscall entry point is reserved (nacl springboard code) */ num_syscalls = ((NACL_TRAMPOLINE_END - NACL_SYSCALL_START_ADDR) / NACL_SYSCALL_BLOCK_SIZE) - 1; ZLOGS(LOG_INSANE, "num_syscalls = %d (0x%x)", num_syscalls, num_syscalls); addr = nap->mem_start + NACL_SYSCALL_START_ADDR; for (i = 0; i < num_syscalls; ++i) { NaClPatchOneTrampoline(nap, addr); addr += NACL_SYSCALL_BLOCK_SIZE; } }
static void FinalDump(struct NaClApp *nap) { ZLOGS(LOG_INSANE, "exiting -- printing NaClApp details"); PrintAppDetails(nap, LOG_INSANE); LogMemMap(nap, LOG_INSANE); SignalHandlerFini(); }
void NaClInitSwitchToApp(struct NaClApp *nap) { int cpu = CPUTest(); UNREFERENCED_PARAMETER(nap); ZLOGFAIL(cpu == -1, EFAULT, "zerovm needs SSE CPU"); NaClSwitch = cpu == 0 ? NaClSwitchSSE : NaClSwitchAVX; ZLOGS(LOG_DEBUG, "%s cpu detected", cpu == 0 ? "SSE" : "AVX"); }
/* d'b: duplicate of trap() exit. remove it when trap() replace syscalls */ int32_t NaClSysExit(struct NaClApp *nap, int status) { ZLOGS(LOG_DEBUG, "Exit syscall handler: %d", status); nap->system_manifest->user_ret_code = status; longjmp(user_exit, status); /* NOTREACHED */ return -EINVAL; }
/* tls create */ int32_t NaClSysTls_Init(struct NaClApp *nap, void *thread_ptr) { uintptr_t sys_tls; ZLOGS(LOG_DEBUG, "tls init with 0x%08lx", (uintptr_t)thread_ptr); /* * Verify that the address in the app's range and translated from * nacl module address to service runtime address - a nop on ARM */ sys_tls = NaClUserToSysAddrRange(nap, (uintptr_t) thread_ptr, 4); ZLOGS(LOG_INSANE, "thread_ptr 0x%p, sys_tls 0x%lx", thread_ptr, sys_tls); if(kNaClBadAddress == sys_tls) return -EFAULT; nap->sys_tls = sys_tls; return 0; }
/* user exit. invokes long jump to main(). uses global var */ static int32_t ZVMExitHandle(struct NaClApp *nap, int32_t code) { assert(nap != NULL); nap->system_manifest->user_ret_code = code; ZLOGS(LOG_DEBUG, "Exit syscall handler: %d", code); longjmp(user_exit, code); return code; /* prevent compiler warning. not reached */ }
/* user exit. session is finished */ static void ZVMExitHandle(struct NaClApp *nap, int32_t code) { assert(nap != NULL); SetUserCode(code); if(GetExitCode() == 0) SetExitState(OK_STATE); ZLOGS(LOG_DEBUG, "SESSION %d RETURNED %d", nap->manifest->node, code); ReportDtor(0); }
static void FinalDump(struct NaClApp *nap) { ZLOGS(LOG_INSANE, "exiting -- printing NaClApp details"); /* NULL can be used because syslog used for nacl log */ PrintAppDetails(nap, (struct Gio *) NULL, LOG_INSANE); LogMemMap(nap, LOG_INSANE); SignalHandlerFini(); }
/* user exit. session is finished */ static int32_t ZVMExitHandle(struct NaClApp *nap, int32_t code) { assert(nap != NULL); nap->system_manifest->user_ret_code = code; ZLOGS(LOG_DEBUG, "SESSION RETURNED %d", code); SetExitState(OK_STATE); NaClExit(0); return 0; /* unreachable */ }
/* * Platform-specific routine to allocate memory space for the NaCl * module. mem is an out argument; addrsp_size is the requested * address space size, currently always ((size_t) 1) << * nap->addr_bits. On x86-64, there's a further requirement that this * is 4G. * * The actual amount of memory allocated is larger than requested on * x86-64 and on the ARM, since guard pages are also allocated to be * contiguous with the allocated address space. * * If successful, the guard pages are not yet memory protected. The * function NaClMprotectGuards must be called for the guard pages to * be active. * * update: abort zvm if failed */ static void NaClAllocateSpace(void **mem, size_t addrsp_size) { size_t mem_sz = 2 * GUARDSIZE + FOURGIG; /* 40G guard on each side */ size_t log_align = ALIGN_BITS; void *mem_ptr; ZLOGS(LOG_INSANE, "NaClAllocateSpace(*, 0x%016lx bytes)", addrsp_size); ZLOGFAIL(addrsp_size != FOURGIG, EFAULT, "addrsp_size != FOURGIG"); errno = 0; mem_ptr = NaClAllocatePow2AlignedMemory(mem_sz, log_align); ZLOGFAIL(NULL == mem_ptr, errno, "NaClAllocatePow2AlignedMemory failed"); /* * The module lives in the middle FOURGIG of the allocated region -- * we skip over an initial 40G guard. */ *mem = (void *)(((char *)mem_ptr) + GUARDSIZE); ZLOGS(LOG_INSANE, "addr space at 0x%016lx", (uintptr_t)*mem); }
static void DumpElfHeader(int loglevel, const Elf_Ehdr *elf_hdr) { ZLOGS(loglevel, "%020o (Elf header) %020o", 0, 0); DUMP(e_ident+1, ".3s"); DUMP(e_type, "#x"); DUMP(e_machine, "#x"); DUMP(e_version, "#x"); DUMP(e_entry, "#x"); DUMP(e_phoff, "#x"); DUMP(e_shoff, "#x"); DUMP(e_flags, "#x"); DUMP(e_ehsize, "#x"); DUMP(e_phentsize, "#x"); DUMP(e_phnum, "#x"); DUMP(e_shentsize, "#x"); DUMP(e_shnum, "#x"); DUMP(e_shstrndx, "#x"); ZLOGS(loglevel, "sizeof(Elf32_Ehdr) = 0x%x", (int) sizeof *elf_hdr); }
/* log zerovm command line */ static void ZVMCommandLine(int argc, char **argv) { char cmd[BIG_ENOUGH_SPACE]; int offset = 0; int i; offset += sprintf(cmd, "zerovm command line:"); for(i = 0; i < argc; ++i) offset += g_snprintf(cmd + offset, BIG_ENOUGH_SPACE - offset, " %s", argv[i]); ZLOGS(LOG_DEBUG, "%s", cmd); }
/* * bind the given channel using info from netlist * returns not 0 if failed * note: replaces PrepareBind if no name service available */ static int DoBind(const struct ChannelDesc* channel) { struct ChannelConnection *record; char buf[BIG_ENOUGH_STRING], *url = buf; record = GetChannelConnectionInfo(channel); assert(record != NULL); MakeURL(url, BIG_ENOUGH_STRING, channel, record); ZLOGS(LOG_DEBUG, "bind url %s", url); return zmq_bind(channel->socket, url); }