1 /*
2  * Copyright 2014 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 #include <assert.h>
8 #include <errno.h>
9 
10 #include "native_client/src/nonsfi/linux/linux_pthread_private.h"
11 #include "native_client/src/nonsfi/linux/linux_syscall_defines.h"
12 #include "native_client/src/nonsfi/linux/linux_syscall_structs.h"
13 #include "native_client/src/nonsfi/linux/linux_syscall_wrappers.h"
14 #include "native_client/src/nonsfi/linux/linux_sys_private.h"
15 #include "native_client/src/public/linux_syscalls/sched.h"
16 #include "native_client/src/public/linux_syscalls/sys/syscall.h"
17 #include "native_client/src/untrusted/nacl/nacl_irt.h"
18 #include "native_client/src/untrusted/nacl/nacl_thread.h"
19 #include "native_client/src/untrusted/pthread/pthread_internal.h"
20 
21 /* Convert a return value of a Linux syscall to the one of an IRT call. */
irt_return_call(uintptr_t result)22 static uint32_t irt_return_call(uintptr_t result) {
23   if (linux_is_error_result(result))
24     return -result;
25   return 0;
26 }
27 
nacl_irt_thread_create_v0_2(void (* start_func)(void),void * stack,void * thread_ptr,nacl_irt_tid_t * child_tid)28 static int nacl_irt_thread_create_v0_2(void (*start_func)(void), void *stack,
29                                        void *thread_ptr,
30                                        nacl_irt_tid_t *child_tid) {
31   /*
32    * We do not use CLONE_CHILD_CLEARTID as we do not want any
33    * non-private futex signaling. Also, NaCl ABI does not require us
34    * to signal the futex on stack_flag.
35    */
36   int flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
37                CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS |
38                CLONE_PARENT_SETTID);
39   /*
40    * In order to avoid allowing clone with and without CLONE_PARENT_SETTID, if
41    * |child_tid| is NULL, we provide a valid pointer whose value will be
42    * ignored.
43    */
44   nacl_irt_tid_t ignored;
45   void *ptid = (child_tid != NULL) ? child_tid : &ignored;
46 
47   /*
48    * linux_clone_wrapper expects start_func's type is "int (*)(void *)".
49    * Although |start_func| has type "void (*)(void)", the type mismatching
50    * will not cause a problem. Passing a dummy |arg| (= 0) does nothing there.
51    * Also, start_func will never return.
52    */
53   return irt_return_call(linux_clone_wrapper(
54       (uintptr_t) start_func, /* arg */ 0, flags, stack,
55       ptid, thread_ptr, /* ctid */ NULL));
56 }
57 
nacl_irt_thread_create(void (* start_func)(void),void * stack,void * thread_ptr)58 static int nacl_irt_thread_create(void (*start_func)(void), void *stack,
59                                   void *thread_ptr) {
60   nacl_irt_tid_t child_tid;
61   return nacl_irt_thread_create_v0_2(start_func, stack, thread_ptr, &child_tid);
62 }
63 
nacl_irt_thread_exit(int32_t * stack_flag)64 static void nacl_irt_thread_exit(int32_t *stack_flag) {
65   /*
66    * We fill zero to stack_flag by ourselves instead of relying
67    * on CLONE_CHILD_CLEARTID. We do everything in the following inline
68    * assembly because we need to make sure we will never touch stack.
69    *
70    * We will set the stack pointer to zero at the beginning of the
71    * assembly code just in case an async signal arrives after setting
72    * *stack_flag=0 but before calling the syscall, so that any signal
73    * handler crashes rather than running on a stack that has been
74    * reallocated to another thread.
75    */
76 #if defined(__i386__)
77   __asm__ __volatile__("mov $0, %%esp\n"
78                        "movl $0, (%[stack_flag])\n"
79                        "int $0x80\n"
80                        "hlt\n"
81                        :: [stack_flag]"r"(stack_flag), "a"(__NR_exit));
82 #elif defined(__arm__)
83   __asm__ __volatile__("mov sp, #0\n"
84                        "mov r7, #0\n"
85                        "str r7, [%[stack_flag]]\n"
86                        "mov r7, %[sysno]\n"
87                        "svc #0\n"
88                        "bkpt #0\n"
89                        :: [stack_flag]"r"(stack_flag), [sysno]"i"(__NR_exit)
90                        : "r7");
91 #else
92 # error Unsupported architecture
93 #endif
94 }
95 
nacl_irt_thread_nice(const int nice)96 static int nacl_irt_thread_nice(const int nice) {
97   return 0;
98 }
99 
get_irt_tdb(void * thread_ptr)100 static struct nc_combined_tdb *get_irt_tdb(void *thread_ptr) {
101   struct nc_combined_tdb *tdb = (void *) ((uintptr_t) thread_ptr +
102                                           __nacl_tp_tdb_offset(sizeof(*tdb)));
103   return tdb;
104 }
105 
106 /*
107  * This is the real first entry point for new threads.
108  * Based on code from src/untrusted/irt/irt_thread.c
109  */
irt_start_thread()110 static void irt_start_thread() {
111   struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp());
112 
113   /*
114    * Fetch the user's start routine.
115    */
116   void *(*user_start)(void *) = tdb->tdb.start_func;
117 
118   /*
119    * Now do per-thread initialization for the IRT-private C library state.
120    */
121   __newlib_thread_init();
122 
123   /*
124    * Finally, run the user code.
125    */
126   (*user_start)(tdb->tdb.state);
127 
128   /*
129    * That should never return.  Crash hard if it does.
130    */
131   __builtin_trap();
132 }
133 
134 /*
135  * Creates a thread and initializes the IRT-private TLS area.
136  * Based on code from src/untrusted/irt/irt_thread.c
137  */
nacl_user_thread_create(void * (* start_func)(void *),void * stack,void * thread_ptr,nacl_irt_tid_t * child_tid)138 int nacl_user_thread_create(void *(*start_func)(void *), void *stack,
139                             void *thread_ptr, nacl_irt_tid_t *child_tid) {
140   struct nc_combined_tdb *tdb;
141 
142   /*
143    * Before we start the thread, allocate the IRT-private TLS area for it.
144    */
145   size_t combined_size = __nacl_tls_combined_size(sizeof(*tdb));
146   void *combined_area = malloc(combined_size);
147   if (combined_area == NULL)
148     return EAGAIN;
149 
150  /*
151   * Note that __nacl_tls_initialize_memory() is not reversible,
152   * because it takes a pointer that need not be aligned and can
153   * return a pointer that is aligned.  In order to
154   * free(combined_area) later, we must save the value of
155   * combined_area.
156   */
157   void *irt_tp = __nacl_tls_initialize_memory(combined_area, sizeof(*tdb));
158   tdb = get_irt_tdb(irt_tp);
159   __nc_initialize_unjoinable_thread(tdb);
160   tdb->tdb.irt_thread_data = combined_area;
161   tdb->tdb.start_func = start_func;
162   tdb->tdb.state = thread_ptr;
163 
164   return nacl_irt_thread_create_v0_2(irt_start_thread, stack, irt_tp,
165                                      child_tid);
166 }
167 
168 /*
169  * Destroys a thread created by nacl_user_thread_create.
170  * Based on code from src/untrusted/irt/irt_thread.c
171  */
nacl_user_thread_exit(int32_t * stack_flag)172 void nacl_user_thread_exit(int32_t *stack_flag) {
173   struct nc_combined_tdb *tdb = get_irt_tdb(__nacl_read_tp());
174 
175   __nc_tsd_exit();
176 
177   /*
178    * Sanity check: Check that this function was not called on a thread
179    * created by the IRT's internal pthread_create().  For such
180    * threads, irt_thread_data == NULL.
181    */
182   assert(tdb->tdb.irt_thread_data != NULL);
183 
184   free(tdb->tdb.irt_thread_data);
185 
186   nacl_irt_thread_exit(stack_flag);
187 }
188 
__nc_initialize_interfaces(void)189 void __nc_initialize_interfaces(void) {
190   const struct nacl_irt_thread init = {
191     nacl_irt_thread_create,
192     nacl_irt_thread_exit,
193     nacl_irt_thread_nice,
194   };
195   __libnacl_irt_thread = init;
196 }
197