| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <errno.h> | 5 #include <errno.h> |
| 6 #include <pthread.h> | 6 #include <pthread.h> |
| 7 #include <signal.h> |
| 7 #include <stdlib.h> | 8 #include <stdlib.h> |
| 9 #include <sys/mman.h> |
| 8 | 10 |
| 9 #include "base/logging.h" | 11 #include "base/logging.h" |
| 10 #include "base/macros.h" | 12 #include "base/macros.h" |
| 11 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
| 12 #include "components/nacl/loader/nonsfi/irt_interfaces.h" | 14 #include "components/nacl/loader/nonsfi/irt_interfaces.h" |
| 13 #include "native_client/src/trusted/service_runtime/nacl_signal.h" | |
| 14 | 15 |
| 15 namespace nacl { | 16 namespace nacl { |
| 16 namespace nonsfi { | 17 namespace nonsfi { |
| 17 namespace { | 18 namespace { |
| 18 | 19 |
| 19 // We heuristically chose 1M for the stack size per thread. | 20 // We heuristically chose 1M for the stack size per thread. |
| 20 const int kStackSize = 1024 * 1024; | 21 const int kStackSize = 1024 * 1024; |
| 21 | 22 |
| 22 // For RAII of pthread_attr_t. | 23 // For RAII of pthread_attr_t. |
| 23 class ScopedPthreadAttrPtr { | 24 class ScopedPthreadAttrPtr { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 37 void* thread_ptr; | 38 void* thread_ptr; |
| 38 void* signal_stack; | 39 void* signal_stack; |
| 39 }; | 40 }; |
| 40 | 41 |
| 41 // A thread local pointer to support nacl_irt_tls. | 42 // A thread local pointer to support nacl_irt_tls. |
| 42 // This should be initialized at the beginning of ThreadMain, which is a thin | 43 // This should be initialized at the beginning of ThreadMain, which is a thin |
| 43 // wrapper of a user function called on a newly created thread, and may be | 44 // wrapper of a user function called on a newly created thread, and may be |
| 44 // reset via IrtTlsInit(). The pointer can be obtained via IrtTlsGet(). | 45 // reset via IrtTlsInit(). The pointer can be obtained via IrtTlsGet(). |
| 45 __thread void* g_thread_ptr; | 46 __thread void* g_thread_ptr; |
| 46 | 47 |
| 48 const int kSignalStackSize = SIGSTKSZ + 4096; |
| 49 const int kNonSfiPageSize = 4096; // really? |
| 50 const int kStackGuardSize = kNonSfiPageSize; |
| 51 |
| 52 void NaClSignalStackRegister(void *stack) { |
| 53 /* |
| 54 * If we set up signal handlers, we must ensure that any thread that |
| 55 * runs untrusted code has an alternate signal stack set up. The |
| 56 * default for a new thread is to use the stack pointer from the |
| 57 * point at which the fault occurs, but it would not be safe to use |
| 58 * untrusted code's %esp/%rsp value. |
| 59 */ |
| 60 stack_t st; |
| 61 st.ss_size = kSignalStackSize; |
| 62 st.ss_sp = ((uint8_t *) stack) + kStackGuardSize; |
| 63 st.ss_flags = 0; |
| 64 if (sigaltstack(&st, NULL) != 0) { |
| 65 PLOG(FATAL) << "Failed to register signal stack"; |
| 66 } |
| 67 } |
| 68 |
| 69 int NaClSignalStackAllocate(void **result) { |
| 70 /* |
| 71 * We use mmap() to allocate the signal stack for two reasons: |
| 72 * |
| 73 * 1) By page-aligning the memory allocation (which malloc() does |
| 74 * not do for small allocations), we avoid allocating any real |
| 75 * memory in the common case in which the signal handler is never |
| 76 * run. |
| 77 * |
| 78 * 2) We get to create a guard page, to guard against the unlikely |
| 79 * occurrence of the signal handler both overrunning and doing so in |
| 80 * an exploitable way. |
| 81 */ |
| 82 void *stack = mmap(NULL, kSignalStackSize + kStackGuardSize, |
| 83 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, |
| 84 -1, 0); |
| 85 if (stack == MAP_FAILED) { |
| 86 return 0; |
| 87 } |
| 88 /* We assume that the stack grows downwards. */ |
| 89 if (mprotect(stack, kStackGuardSize, PROT_NONE) != 0) { |
| 90 PLOG(FATAL) << "Failed to mprotect() the stack guard page"; |
| 91 } |
| 92 *result = stack; |
| 93 return 1; |
| 94 } |
| 95 |
| 47 void* ThreadMain(void *arg) { | 96 void* ThreadMain(void *arg) { |
| 48 ::scoped_ptr<ThreadContext> context(static_cast<ThreadContext*>(arg)); | 97 ::scoped_ptr<ThreadContext> context(static_cast<ThreadContext*>(arg)); |
| 49 g_thread_ptr = context->thread_ptr; | 98 g_thread_ptr = context->thread_ptr; |
| 50 | 99 |
| 51 DVLOG(4) << "Registering alternate signal stack: " << context->signal_stack; | 100 DVLOG(4) << "Registering alternate signal stack: " << context->signal_stack; |
| 52 NaClSignalStackRegister(context->signal_stack); | 101 NaClSignalStackRegister(context->signal_stack); |
| 53 | 102 |
| 54 // Release the memory of context before running start_func. | 103 // Release the memory of context before running start_func. |
| 55 void (*start_func)() = context->start_func; | 104 void (*start_func)() = context->start_func; |
| 56 context.reset(); | 105 context.reset(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 87 error = pthread_create(&tid, &attr, ThreadMain, context.get()); | 136 error = pthread_create(&tid, &attr, ThreadMain, context.get()); |
| 88 if (error != 0) | 137 if (error != 0) |
| 89 return error; | 138 return error; |
| 90 | 139 |
| 91 // The ownership of the context is taken by the created thread. So, here we | 140 // The ownership of the context is taken by the created thread. So, here we |
| 92 // just manually release it. | 141 // just manually release it. |
| 93 ignore_result(context.release()); | 142 ignore_result(context.release()); |
| 94 return 0; | 143 return 0; |
| 95 } | 144 } |
| 96 | 145 |
| 146 void* NaClSignalStackUnregister(void) { |
| 147 /* |
| 148 * Unregister the signal stack in case a fault occurs between the |
| 149 * thread deallocating the signal stack and exiting. Such a fault |
| 150 * could be unsafe if the address space were reallocated before the |
| 151 * fault, although that is unlikely. |
| 152 */ |
| 153 stack_t st; |
| 154 st.ss_size = 0; |
| 155 st.ss_sp = NULL; |
| 156 st.ss_flags = SS_DISABLE; |
| 157 stack_t old_stack; |
| 158 if (sigaltstack(&st, &old_stack) != 0) { |
| 159 PLOG(FATAL) << "Failed to unregister signal stack."; |
| 160 } |
| 161 return old_stack.ss_sp; |
| 162 } |
| 163 |
| 164 void NaClSignalStackFree(void *stack) { |
| 165 CHECK(stack != NULL); |
| 166 if (munmap(stack, kSignalStackSize + kStackGuardSize) != 0) { |
| 167 PLOG(FATAL) << "Failed to munmap() signal stack."; |
| 168 } |
| 169 } |
| 170 |
| 97 void IrtThreadExit(int32_t* stack_flag) { | 171 void IrtThreadExit(int32_t* stack_flag) { |
| 98 // As we actually don't use stack given to thread_create, it means that the | 172 // As we actually don't use stack given to thread_create, it means that the |
| 99 // memory can be released whenever. | 173 // memory can be released whenever. |
| 100 if (stack_flag) | 174 if (stack_flag) |
| 101 *stack_flag = 0; | 175 *stack_flag = 0; |
| 176 NaClSignalStackUnregister(); |
| 177 // TODO: How do I know altstack address ? Should I trust sigaltstack |
| 178 // return value ? |
| 179 // NaClSignalStackFree(signal_stack); |
| 102 pthread_exit(NULL); | 180 pthread_exit(NULL); |
| 103 } | 181 } |
| 104 | 182 |
| 105 int IrtThreadNice(const int nice) { | 183 int IrtThreadNice(const int nice) { |
| 106 // TODO(https://code.google.com/p/nativeclient/issues/detail?id=3734): | 184 // TODO(https://code.google.com/p/nativeclient/issues/detail?id=3734): |
| 107 // Implement this method. | 185 // Implement this method. |
| 108 // Note that this is just a hint, so here we just return success without | 186 // Note that this is just a hint, so here we just return success without |
| 109 // do anything. | 187 // do anything. |
| 110 return 0; | 188 return 0; |
| 111 } | 189 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 127 IrtThreadNice, | 205 IrtThreadNice, |
| 128 }; | 206 }; |
| 129 | 207 |
| 130 const nacl_irt_tls kIrtTls = { | 208 const nacl_irt_tls kIrtTls = { |
| 131 IrtTlsInit, | 209 IrtTlsInit, |
| 132 IrtTlsGet, | 210 IrtTlsGet, |
| 133 }; | 211 }; |
| 134 | 212 |
| 135 } // namespace nonsfi | 213 } // namespace nonsfi |
| 136 } // namespace nacl | 214 } // namespace nacl |
| OLD | NEW |