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 |