1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl Server Runtime user thread state.
9 : */
10 :
11 : #include <string.h>
12 :
13 : #include "native_client/src/shared/platform/aligned_malloc.h"
14 : #include "native_client/src/shared/platform/nacl_check.h"
15 : #include "native_client/src/shared/platform/nacl_exit.h"
16 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
17 :
18 : #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
19 : #include "native_client/src/trusted/service_runtime/nacl_desc_effector_ldr.h"
20 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
21 : #include "native_client/src/trusted/service_runtime/nacl_tls.h"
22 : #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h"
23 : #include "native_client/src/trusted/service_runtime/nacl_stack_safety.h"
24 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
25 : #include "native_client/src/trusted/service_runtime/osx/mach_thread_map.h"
26 :
27 :
28 20880 : void WINAPI NaClAppThreadLauncher(void *state) {
29 20880 : struct NaClAppThread *natp = (struct NaClAppThread *) state;
30 20880 : uint32_t thread_idx;
31 20880 : NaClLog(4, "NaClAppThreadLauncher: entered\n");
32 :
33 20880 : NaClSignalStackRegister(natp->signal_stack);
34 :
35 20880 : NaClLog(4, " natp = 0x%016"NACL_PRIxPTR"\n", (uintptr_t) natp);
36 20880 : NaClLog(4, " prog_ctr = 0x%016"NACL_PRIxNACL_REG"\n", natp->user.prog_ctr);
37 20880 : NaClLog(4, "stack_ptr = 0x%016"NACL_PRIxPTR"\n",
38 20880 : NaClGetThreadCtxSp(&natp->user));
39 :
40 20880 : thread_idx = NaClGetThreadIdx(natp);
41 62642 : CHECK(0 < thread_idx);
42 62640 : CHECK(thread_idx < NACL_THREAD_MAX);
43 20881 : NaClTlsSetCurrentThread(natp);
44 20881 : nacl_user[thread_idx] = &natp->user;
45 : #if NACL_WINDOWS
46 : nacl_thread_ids[thread_idx] = GetCurrentThreadId();
47 : #elif NACL_OSX
48 20881 : NaClSetCurrentMachThreadForThreadIndex(thread_idx);
49 : #endif
50 :
51 : /*
52 : * We have to hold the threads_mu lock until after thread_num field
53 : * in this thread has been initialized. All other threads can only
54 : * find and examine this natp through the threads table, so the fact
55 : * that natp is not consistent (no thread_num) will not be visible.
56 : */
57 20881 : NaClXMutexLock(&natp->nap->threads_mu);
58 20881 : natp->thread_num = NaClAddThreadMu(natp->nap, natp);
59 20881 : NaClXMutexUnlock(&natp->nap->threads_mu);
60 :
61 20881 : NaClVmHoleThreadStackIsSafe(natp->nap);
62 :
63 20881 : NaClStackSafetyNowOnUntrustedStack();
64 :
65 : /*
66 : * Notify the debug stub, that a new thread is availible.
67 : */
68 20881 : if (NULL != natp->nap->debug_stub_callbacks) {
69 20 : natp->nap->debug_stub_callbacks->thread_create_hook(natp);
70 20 : }
71 :
72 : /*
73 : * After this NaClAppThreadSetSuspendState() call, we should not
74 : * claim any mutexes, otherwise we risk deadlock.
75 : */
76 0 : NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_TRUSTED,
77 : NACL_APP_THREAD_UNTRUSTED);
78 :
79 0 : NaClStartThreadInApp(natp, natp->user.prog_ctr);
80 0 : }
81 :
82 :
83 : /*
84 : * natp should be thread_self(), called while holding no locks.
85 : */
86 20845 : void NaClAppThreadTeardown(struct NaClAppThread *natp) {
87 20845 : struct NaClApp *nap;
88 20845 : size_t thread_idx;
89 :
90 : /*
91 : * mark this thread as dead; doesn't matter if some other thread is
92 : * asking us to commit suicide.
93 : */
94 20845 : NaClLog(3, "NaClAppThreadTeardown(0x%08"NACL_PRIxPTR")\n",
95 : (uintptr_t) natp);
96 20845 : nap = natp->nap;
97 20845 : if (NULL != nap->debug_stub_callbacks) {
98 3 : NaClLog(3, " notifying the debug stub of the thread exit\n");
99 : /*
100 : * This must happen before deallocating the ID natp->thread_num.
101 : * We have the invariant that debug stub lock should be acquired before
102 : * nap->threads_mu lock. Hence we must not hold threads_mu lock while
103 : * calling debug stub hooks.
104 : */
105 3 : nap->debug_stub_callbacks->thread_exit_hook(natp);
106 3 : }
107 :
108 20845 : NaClLog(3, " getting thread table lock\n");
109 20845 : NaClXMutexLock(&nap->threads_mu);
110 20845 : NaClLog(3, " getting thread lock\n");
111 20845 : NaClXMutexLock(&natp->mu);
112 : /*
113 : * Remove ourselves from the ldt-indexed global tables. The ldt
114 : * entry is released as part of NaClAppThreadDelete(), and if
115 : * another thread is immediately created (from some other running
116 : * thread) we want to be sure that any ldt-based lookups will not
117 : * reach this dying thread's data.
118 : */
119 20845 : thread_idx = NaClGetThreadIdx(natp);
120 : /*
121 : * On x86-64 and ARM, clearing nacl_user entry ensures that we will
122 : * fault if another syscall is made with this thread_idx. In
123 : * particular, thread_idx 0 is never used.
124 : */
125 20845 : nacl_user[thread_idx] = NULL;
126 : #if NACL_WINDOWS
127 : nacl_thread_ids[thread_idx] = 0;
128 : #elif NACL_OSX
129 20845 : NaClClearMachThreadForThreadIndex(thread_idx);
130 : #endif
131 : /*
132 : * Unset the TLS variable so that if a crash occurs during thread
133 : * teardown, the signal handler does not dereference a dangling
134 : * NaClAppThread pointer.
135 : */
136 20845 : NaClTlsSetCurrentThread(NULL);
137 :
138 20845 : NaClLog(3, " removing thread from thread table\n");
139 : /* Deallocate the ID natp->thread_num. */
140 20845 : NaClRemoveThreadMu(nap, natp->thread_num);
141 20845 : NaClLog(3, " unlocking thread\n");
142 20845 : NaClXMutexUnlock(&natp->mu);
143 20845 : NaClLog(3, " unlocking thread table\n");
144 20845 : NaClXMutexUnlock(&nap->threads_mu);
145 20845 : NaClLog(3, " unregistering signal stack\n");
146 20845 : NaClSignalStackUnregister();
147 20845 : NaClLog(3, " freeing thread object\n");
148 20845 : NaClAppThreadDelete(natp);
149 20845 : NaClLog(3, " NaClThreadExit\n");
150 20845 : NaClThreadExit();
151 20845 : NaClLog(LOG_FATAL,
152 : "NaClAppThreadTeardown: NaClThreadExit() should not return\n");
153 : /* NOTREACHED */
154 20845 : }
155 :
156 :
157 20881 : struct NaClAppThread *NaClAppThreadMake(struct NaClApp *nap,
158 20881 : uintptr_t usr_entry,
159 20881 : uintptr_t usr_stack_ptr,
160 20881 : uint32_t user_tls1,
161 20881 : uint32_t user_tls2) {
162 20881 : struct NaClAppThread *natp;
163 :
164 20881 : natp = NaClAlignedMalloc(sizeof *natp, __alignof(struct NaClAppThread));
165 20881 : if (natp == NULL) {
166 0 : return NULL;
167 : }
168 :
169 20881 : NaClLog(4, " natp = 0x%016"NACL_PRIxPTR"\n", (uintptr_t) natp);
170 20881 : NaClLog(4, " nap = 0x%016"NACL_PRIxPTR"\n", (uintptr_t) nap);
171 20881 : NaClLog(4, "usr_stack_ptr = 0x%016"NACL_PRIxPTR"\n", usr_stack_ptr);
172 :
173 : /*
174 : * Set these early, in case NaClTlsAllocate() wants to examine them.
175 : */
176 20881 : natp->nap = nap;
177 20881 : natp->thread_num = -1; /* illegal index */
178 20881 : natp->host_thread_is_defined = 0;
179 62643 : memset(&natp->host_thread, 0, sizeof(natp->host_thread));
180 :
181 20881 : if (!NaClAppThreadInitArchSpecific(natp, usr_entry, usr_stack_ptr)) {
182 0 : goto cleanup_free;
183 : }
184 :
185 20881 : NaClTlsSetTlsValue1(natp, user_tls1);
186 20881 : NaClTlsSetTlsValue2(natp, user_tls2);
187 :
188 20881 : natp->signal_stack = NULL;
189 20881 : natp->exception_stack = 0;
190 20881 : natp->exception_flag = 0;
191 :
192 20881 : if (!NaClMutexCtor(&natp->mu)) {
193 0 : goto cleanup_free;
194 : }
195 :
196 20881 : if (!NaClSignalStackAllocate(&natp->signal_stack)) {
197 0 : goto cleanup_mu;
198 : }
199 :
200 20881 : if (!NaClMutexCtor(&natp->suspend_mu)) {
201 0 : goto cleanup_mu;
202 : }
203 20881 : natp->suspend_state = NACL_APP_THREAD_TRUSTED;
204 20881 : natp->suspended_registers = NULL;
205 20881 : natp->fault_signal = 0;
206 :
207 20881 : natp->dynamic_delete_generation = 0;
208 :
209 20881 : if (!NaClCondVarCtor(&natp->futex_condvar)) {
210 0 : goto cleanup_suspend_mu;
211 : }
212 20881 : return natp;
213 :
214 : cleanup_suspend_mu:
215 0 : NaClMutexDtor(&natp->suspend_mu);
216 : cleanup_mu:
217 0 : NaClMutexDtor(&natp->mu);
218 0 : if (NULL != natp->signal_stack) {
219 0 : NaClSignalStackFree(&natp->signal_stack);
220 0 : natp->signal_stack = NULL;
221 0 : }
222 : cleanup_free:
223 0 : NaClAlignedFree(natp);
224 0 : return NULL;
225 20881 : }
226 :
227 :
228 20881 : int NaClAppThreadSpawn(struct NaClApp *nap,
229 20881 : uintptr_t usr_entry,
230 20881 : uintptr_t usr_stack_ptr,
231 20881 : uint32_t user_tls1,
232 20881 : uint32_t user_tls2) {
233 20881 : struct NaClAppThread *natp = NaClAppThreadMake(nap, usr_entry, usr_stack_ptr,
234 : user_tls1, user_tls2);
235 20881 : if (natp == NULL) {
236 0 : return 0;
237 : }
238 : /*
239 : * We set host_thread_is_defined assuming, for now, that
240 : * NaClThreadCtor() will succeed.
241 : */
242 20881 : natp->host_thread_is_defined = 1;
243 20881 : if (!NaClThreadCtor(&natp->host_thread, NaClAppThreadLauncher, (void *) natp,
244 : NACL_KERN_STACK_SIZE)) {
245 : /*
246 : * No other thread saw the NaClAppThread, so it is OK that
247 : * host_thread was not initialized despite host_thread_is_defined
248 : * being set.
249 : */
250 0 : natp->host_thread_is_defined = 0;
251 0 : NaClAppThreadDelete(natp);
252 0 : return 0;
253 : }
254 20881 : return 1;
255 20881 : }
256 :
257 :
258 20291 : void NaClAppThreadDelete(struct NaClAppThread *natp) {
259 : /*
260 : * the thread must not be still running, else this crashes the system
261 : */
262 :
263 20291 : if (natp->host_thread_is_defined) {
264 20291 : NaClThreadDtor(&natp->host_thread);
265 20291 : }
266 20291 : free(natp->suspended_registers);
267 20291 : NaClMutexDtor(&natp->suspend_mu);
268 20291 : NaClSignalStackFree(natp->signal_stack);
269 20291 : natp->signal_stack = NULL;
270 20291 : NaClCondVarDtor(&natp->futex_condvar);
271 20291 : NaClTlsFree(natp);
272 20291 : NaClMutexDtor(&natp->mu);
273 20291 : NaClAlignedFree(natp);
274 20291 : }
|