static struct Gio *NaClLogGioFromFileIoBuffer(FILE *log_iob) { struct GioFile *log_gio; log_gio = malloc(sizeof *log_gio); if (NULL == log_gio) { perror("NaClLogSetFile"); fprintf(stderr, "No memory for log buffers\n"); NaClAbort(); } if (!GioFileRefCtor(log_gio, log_iob)) { fprintf(stderr, "NaClLog module internal error: GioFileRefCtor failed\n"); NaClAbort(); } return (struct Gio *) log_gio; }
static FILE *NaClLogFileIoBufferFromFile(char const *log_file) { int log_desc; FILE *log_iob; log_desc = open(log_file, O_WRONLY | O_APPEND | O_CREAT, 0777); if (-1 == log_desc) { perror("NaClLogSetFile"); fprintf(stderr, "Could not create log file\n"); NaClAbort(); } log_iob = FDOPEN(log_desc, "a"); if (NULL == log_iob) { perror("NaClLogSetFile"); fprintf(stderr, "Could not fdopen log stream\n"); NaClAbort(); } return log_iob; }
static void HandleSuspendSignal(struct NaClSignalContext *regs) { uint32_t tls_idx = NaClTlsGetIdx(); struct NaClAppThread *natp = nacl_thread[tls_idx]; struct NaClSignalContext *suspended_registers = &natp->suspended_registers->context; /* Sanity check. */ if (natp->suspend_state != (NACL_APP_THREAD_UNTRUSTED | NACL_APP_THREAD_SUSPENDING)) { NaClSignalErrorMessage("HandleSuspendSignal: " "Unexpected suspend_state\n"); NaClAbort(); } if (suspended_registers != NULL) { *suspended_registers = *regs; /* * Ensure that the change to natp->suspend_state does not become * visible before the change to natp->suspended_registers. */ NaClWriteMemoryBarrier(); } /* * Indicate that we have suspended by setting * NACL_APP_THREAD_SUSPENDED. We should not need an atomic * operation for this since the calling thread will not be trying to * change suspend_state. */ natp->suspend_state |= NACL_APP_THREAD_SUSPENDED; FutexWake(&natp->suspend_state, 1); /* Wait until we are asked to resume. */ while (1) { Atomic32 state = natp->suspend_state; if ((state & NACL_APP_THREAD_SUSPENDED) != 0) { FutexWait(&natp->suspend_state, state); continue; /* Retry */ } break; } /* * Apply register modifications. We need to use a snapshot of * natp->suspended_registers because, since we were asked to resume, * we could have been asked to suspend again, and * suspended_registers could have been allocated in the new * suspension request but not in the original suspension request. */ if (suspended_registers != NULL) { *regs = *suspended_registers; } }
void NaClLogUnlock(void) { int run_abort_behavior = 0; switch (g_abort_count) { case 0: NaClXMutexUnlock(&log_mu); break; case 1: /* * include an easy-to-recognize output for the fuzzer to recognize */ if (!g_abort_behavior_active) { NaClLog_mu(LOG_ERROR, "LOG_FATAL abort exit\n"); g_abort_behavior_active = 1; run_abort_behavior = 1; /* * run abort behavior only on edge transition when * g_abort_behavior_active is first set. */ } NaClXMutexUnlock(&log_mu); if (run_abort_behavior) { #ifdef __COVERITY__ NaClAbort(); /* help coverity figure out that this is the default */ #else NaClLogRunAbortBehavior(); #endif /* The abort behavior hook may not abort, so abort here in case. */ NaClAbort(); } break; default: /* * Abort handling code in turn aborted. Eeep! */ NaClAbort(); break; } }
static void HandleUntrustedFault(int signal, struct NaClSignalContext *regs, struct NaClAppThread *natp) { /* Sanity check. */ if ((natp->suspend_state & NACL_APP_THREAD_UNTRUSTED) == 0) { NaClSignalErrorMessage("HandleUntrustedFault: Unexpected suspend_state\n"); NaClAbort(); } /* Notify the debug stub by marking this thread as faulted. */ natp->fault_signal = signal; AtomicIncrement(&natp->nap->faulted_thread_count, 1); /* * We now expect the debug stub to suspend this thread via the * thread suspension API. This will allow the debug stub to get the * register state at the point the fault happened. The debug stub * will be able to modify the register state before unblocking the * thread using NaClAppThreadUnblockIfFaulted(). */ do { int new_signal; sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, NACL_THREAD_SUSPEND_SIGNAL); if (sigwait(&sigset, &new_signal) != 0) { NaClSignalErrorMessage("HandleUntrustedFault: sigwait() failed\n"); NaClAbort(); } if (new_signal != NACL_THREAD_SUSPEND_SIGNAL) { NaClSignalErrorMessage("HandleUntrustedFault: " "sigwait() returned unexpected result\n"); NaClAbort(); } HandleSuspendSignal(regs); } while (natp->fault_signal != 0); }
void NaClErrorLogHookInit(void (*hook)(void *state, char *buf, size_t buf_bytes), void *state) { NaClLog(2, "NaClErrorLogHookInit: entered\n"); if (!NaClErrorGioCtor(&g_NaCl_log_gio, NaClLogGetGio())) { fprintf(stderr, "sel_main_chrome: log reporting setup failed\n"); NaClAbort(); } g_NaCl_log_abort_fn = hook; g_NaCl_log_abort_state = state; NaClLogSetGio((struct Gio *) &g_NaCl_log_gio); NaClLogSetAbortBehavior(NaClReportLogMessages); }
/* * d'b: make syscall invoked from the untrusted code */ NORETURN void NaClSyscallCSegHook() { struct NaClApp *nap; struct NaClThreadContext *user; uintptr_t tramp_ret; nacl_reg_t user_ret; size_t sysnum; uintptr_t sp_user; uintptr_t sp_sys; /* * d'b: nexe just invoked some syscall. stop cpu time counting * increase syscalls counter (correction for setup call will be * corrected later). small mallocs and other calls which are * not really "system" will be accounted anyway! */ nap = gnap; /* restore NaClApp object */ nap->user_side_flag = 1; /* set "user side call" mark */ PauseCpuClock(nap); AccountingSyscallsInc(nap); user = nacl_user; /* restore from global */ sp_user = NaClGetThreadCtxSp(user); sp_sys = NaClUserToSysStackAddr(nap, sp_user); /* * sp_sys points to the top of user stack where there is a retaddr to * trampoline slot */ tramp_ret = *(uintptr_t *)sp_sys; tramp_ret = NaClUserToSysStackAddr(nap, tramp_ret); sysnum = (tramp_ret - (nap->mem_start + NACL_SYSCALL_START_ADDR)) >> NACL_SYSCALL_BLOCK_SHIFT; /* * getting user return address (the address where we need to return after * system call) from the user stack. (see stack layout above) */ user_ret = *(uintptr_t *) (sp_sys + NACL_USERRET_FIX); /* * Fix the user stack, throw away return addresses from the top of the stack. * After this fix, the first argument to a system call must be on the top of * the user stack (see user stack layout above) */ sp_sys += NACL_SYSARGS_FIX; sp_user += NACL_SYSCALLRET_FIX; NaClSetThreadCtxSp(user, sp_user); /* debug print to log */ NaClLog(4, "system call number %"NACL_PRIdS"\n", sysnum); if (sysnum >= NACL_MAX_SYSCALLS) { NaClLog(2, "INVALID system call %"NACL_PRIdS"\n", sysnum); nap->sysret = -NACL_ABI_EINVAL; } else { /* * syscall_args is used by Decoder functions in * nacl_syscall_handlers.c which is automatically generated file * and placed in the * scons-out/.../gen/src/service_runtime/ * directory. syscall_args must point to the first argument of a * system call. System call arguments are placed on the untrusted * user stack. */ nap->syscall_args = (uintptr_t *) sp_sys; nap->sysret = (*(nap->syscall_table[sysnum].handler))(nap); } /* * before switching back to user module, we need to make sure that the * user_ret is properly sandboxed. */ user_ret = (nacl_reg_t) NaClSandboxCodeAddr(nap, (uintptr_t)user_ret); /* d'b: give control to the nexe. start cpu time counting */ ResumeCpuClock(nap); nap->user_side_flag = 0; /* remove "user side call" mark */ NaClSwitchToApp(nap, user_ret); /* NOTREACHED */ fprintf(stderr, "NORETURN NaClSwitchToApp returned!?!\n"); NaClAbort(); }
NORETURN void NaClSyscallCSegHook(int32_t tls_idx) { struct NaClAppThread *natp; struct NaClApp *nap; uintptr_t tramp_ret; size_t sysnum; uintptr_t sp_user; uint32_t sysret; /* * Mark the thread as running on a trusted stack as soon as possible * so that we can report any crashes that occur after this point. */ NaClStackSafetyNowOnTrustedStack(); natp = nacl_thread[tls_idx]; HandleStackContext(natp, &tramp_ret, &sp_user); /* * Before this call, the thread could be suspended, so we should not * lock any mutexes before this, otherwise it could cause a * deadlock. */ NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_UNTRUSTED, NACL_APP_THREAD_TRUSTED); nap = natp->nap; NaClLog(4, "Entered NaClSyscallCSegHook\n"); NaClLog(4, "user sp %"NACL_PRIxPTR"\n", sp_user); NaClCopyInTakeLock(nap); /* * held until syscall args are copied, which occurs in the generated * code. */ sysnum = (tramp_ret - (nap->mem_start + NACL_SYSCALL_START_ADDR)) >> NACL_SYSCALL_BLOCK_SHIFT; NaClLog(4, "system call %"NACL_PRIuS"\n", sysnum); /* * usr_syscall_args is used by Decoder functions in * nacl_syscall_handlers.c which is automatically generated file and * placed in the * scons-out/.../gen/native_client/src/trusted/service_runtime/ * directory. usr_syscall_args must point to the first argument of * a system call. System call arguments are placed on the untrusted * user stack. * * We save the user address for user syscall arguments fetching and * for VM range locking. */ natp->usr_syscall_args = NaClRawUserStackAddrNormalize(sp_user + NACL_SYSARGS_FIX); if (sysnum >= NACL_MAX_SYSCALLS) { NaClLog(2, "INVALID system call %"NACL_PRIdS"\n", sysnum); sysret = -NACL_ABI_EINVAL; NaClCopyInDropLock(nap); } else { NaClLog(4, "making system call %"NACL_PRIdS", " "handler 0x%08"NACL_PRIxPTR"\n", sysnum, (uintptr_t) nap->syscall_table[sysnum].handler); sysret = (*(nap->syscall_table[sysnum].handler))(natp); /* Implicitly drops lock */ } NaClLog(4, ("returning from system call %"NACL_PRIdS", return value %"NACL_PRId32 " (0x%"NACL_PRIx32")\n"), sysnum, sysret, sysret); natp->user.sysret = sysret; NaClLog(4, "return target 0x%08"NACL_PRIxNACL_REG"\n", natp->user.new_prog_ctr); NaClLog(4, "user sp %"NACL_PRIxPTR"\n", sp_user); /* * After this NaClAppThreadSetSuspendState() call, we should not * claim any mutexes, otherwise we risk deadlock. Note that if * NACLVERBOSITY is set high enough to enable the NaClLog() calls in * NaClSwitchToApp(), these calls could deadlock. */ NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_TRUSTED, NACL_APP_THREAD_UNTRUSTED); NaClStackSafetyNowOnUntrustedStack(); NaClSwitchToApp(natp); /* NOTREACHED */ fprintf(stderr, "NORETURN NaClSwitchToApp returned!?!\n"); NaClAbort(); }