| Index: components/nacl/loader/nonsfi/irt_thread.cc
|
| diff --git a/components/nacl/loader/nonsfi/irt_thread.cc b/components/nacl/loader/nonsfi/irt_thread.cc
|
| index b7f5c9a7e03c7dd708f630acc3f652260c4c13f4..c47eabdaba5d3acb47c527e0b3bd553616c79baa 100644
|
| --- a/components/nacl/loader/nonsfi/irt_thread.cc
|
| +++ b/components/nacl/loader/nonsfi/irt_thread.cc
|
| @@ -4,13 +4,14 @@
|
|
|
| #include <errno.h>
|
| #include <pthread.h>
|
| +#include <signal.h>
|
| #include <stdlib.h>
|
| +#include <sys/mman.h>
|
|
|
| #include "base/logging.h"
|
| #include "base/macros.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "components/nacl/loader/nonsfi/irt_interfaces.h"
|
| -#include "native_client/src/trusted/service_runtime/nacl_signal.h"
|
|
|
| namespace nacl {
|
| namespace nonsfi {
|
| @@ -44,6 +45,54 @@ struct ThreadContext {
|
| // reset via IrtTlsInit(). The pointer can be obtained via IrtTlsGet().
|
| __thread void* g_thread_ptr;
|
|
|
| +const int kSignalStackSize = SIGSTKSZ + 4096;
|
| +const int kNonSfiPageSize = 4096; // really?
|
| +const int kStackGuardSize = kNonSfiPageSize;
|
| +
|
| +void NaClSignalStackRegister(void *stack) {
|
| + /*
|
| + * If we set up signal handlers, we must ensure that any thread that
|
| + * runs untrusted code has an alternate signal stack set up. The
|
| + * default for a new thread is to use the stack pointer from the
|
| + * point at which the fault occurs, but it would not be safe to use
|
| + * untrusted code's %esp/%rsp value.
|
| + */
|
| + stack_t st;
|
| + st.ss_size = kSignalStackSize;
|
| + st.ss_sp = ((uint8_t *) stack) + kStackGuardSize;
|
| + st.ss_flags = 0;
|
| + if (sigaltstack(&st, NULL) != 0) {
|
| + PLOG(FATAL) << "Failed to register signal stack";
|
| + }
|
| +}
|
| +
|
| +int NaClSignalStackAllocate(void **result) {
|
| + /*
|
| + * We use mmap() to allocate the signal stack for two reasons:
|
| + *
|
| + * 1) By page-aligning the memory allocation (which malloc() does
|
| + * not do for small allocations), we avoid allocating any real
|
| + * memory in the common case in which the signal handler is never
|
| + * run.
|
| + *
|
| + * 2) We get to create a guard page, to guard against the unlikely
|
| + * occurrence of the signal handler both overrunning and doing so in
|
| + * an exploitable way.
|
| + */
|
| + void *stack = mmap(NULL, kSignalStackSize + kStackGuardSize,
|
| + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
|
| + -1, 0);
|
| + if (stack == MAP_FAILED) {
|
| + return 0;
|
| + }
|
| + /* We assume that the stack grows downwards. */
|
| + if (mprotect(stack, kStackGuardSize, PROT_NONE) != 0) {
|
| + PLOG(FATAL) << "Failed to mprotect() the stack guard page";
|
| + }
|
| + *result = stack;
|
| + return 1;
|
| +}
|
| +
|
| void* ThreadMain(void *arg) {
|
| ::scoped_ptr<ThreadContext> context(static_cast<ThreadContext*>(arg));
|
| g_thread_ptr = context->thread_ptr;
|
| @@ -94,11 +143,40 @@ int IrtThreadCreate(void (*start_func)(), void* stack, void* thread_ptr) {
|
| return 0;
|
| }
|
|
|
| +void* NaClSignalStackUnregister(void) {
|
| + /*
|
| + * Unregister the signal stack in case a fault occurs between the
|
| + * thread deallocating the signal stack and exiting. Such a fault
|
| + * could be unsafe if the address space were reallocated before the
|
| + * fault, although that is unlikely.
|
| + */
|
| + stack_t st;
|
| + st.ss_size = 0;
|
| + st.ss_sp = NULL;
|
| + st.ss_flags = SS_DISABLE;
|
| + stack_t old_stack;
|
| + if (sigaltstack(&st, &old_stack) != 0) {
|
| + PLOG(FATAL) << "Failed to unregister signal stack.";
|
| + }
|
| + return old_stack.ss_sp;
|
| +}
|
| +
|
| +void NaClSignalStackFree(void *stack) {
|
| + CHECK(stack != NULL);
|
| + if (munmap(stack, kSignalStackSize + kStackGuardSize) != 0) {
|
| + PLOG(FATAL) << "Failed to munmap() signal stack.";
|
| + }
|
| +}
|
| +
|
| void IrtThreadExit(int32_t* stack_flag) {
|
| // As we actually don't use stack given to thread_create, it means that the
|
| // memory can be released whenever.
|
| if (stack_flag)
|
| *stack_flag = 0;
|
| + NaClSignalStackUnregister();
|
| + // TODO: How do I know altstack address ? Should I trust sigaltstack
|
| + // return value ?
|
| + // NaClSignalStackFree(signal_stack);
|
| pthread_exit(NULL);
|
| }
|
|
|
|
|