static void FindAndRunHandler(int sig, siginfo_t *info, void *uc) { if (NaClSignalHandlerFind(sig, uc) == NACL_SIGNAL_SEARCH) { int a; /* If we need to keep searching, try the old signal handler. */ for (a = 0; a < SIGNAL_COUNT; a++) { /* If we handle this signal */ if (s_Signals[a] == sig) { /* If this is a real sigaction pointer... */ if (s_OldActions[a].sa_flags & SA_SIGINFO) { /* then call the old handler. */ s_OldActions[a].sa_sigaction(sig, info, uc); break; } /* otherwise check if it is a real signal pointer */ if ((s_OldActions[a].sa_handler != SIG_DFL) && (s_OldActions[a].sa_handler != SIG_IGN)) { /* and call the old signal. */ s_OldActions[a].sa_handler(sig); break; } /* * We matched the signal, but didn't handle it, so we emulate * the default behavior which is to exit the app with the signal * number as the error code. */ NaClSignalErrorMessage("Failed to handle signal.\n"); NaClExit(-sig); } } } }
void NaClSignalHandlerInit() { int a; /* Build the free list */ for (a = 0; a < MAX_NACL_HANDLERS; a++) { s_SignalNodes[a].next = s_FreeList; s_SignalNodes[a].id = a + 1; s_FreeList = &s_SignalNodes[a]; } NaClSignalHandlerInitPlatform(); #ifdef NACL_STANDALONE /* In stand-alone mode (sel_ldr) we handle all signals. */ NaClSignalHandlerAdd(NaClSignalHandleAll); #else /* * When run in Chrome we handle only signals in untrusted code. * Signals in trusted code are allowed to pass back to Chrome so * that Breakpad can create a minidump when applicable. */ NaClSignalHandlerAdd(NaClSignalHandleUntrusted); #endif if (getenv("NACL_CRASH_TEST") != NULL) { NaClSignalErrorMessage("[CRASH_TEST] Causing crash in NaCl " "trusted code...\n"); /* Clang removes non-volatile NULL pointer references. */ *(volatile int *) 0 = 0; } }
enum NaClSignalResult NaClSignalHandleUntrusted(int signal, void *ctx) { struct NaClSignalContext sigCtx; char tmp[128]; /* * Return an 8 bit error code which is -signal to * simulate normal OS behavior */ NaClSignalContextFromHandler(&sigCtx, ctx); if (NaClSignalContextIsUntrusted(&sigCtx)) { SNPRINTF(tmp, sizeof(tmp), "\n** Signal %d from untrusted code: Halting " "at %" NACL_PRIXNACL_REG "h\n", signal, sigCtx.prog_ctr); NaClSignalErrorMessage(tmp); NaClExit((-signal) & 0xFF); } else { SNPRINTF(tmp, sizeof(tmp), "\n** Signal %d from trusted code: Continuing " "from %" NACL_PRIXNACL_REG "h\n", signal, sigCtx.prog_ctr); NaClSignalErrorMessage(tmp); } return NACL_SIGNAL_SEARCH; }
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; } }
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); }