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 service run-time.
9  */
10 
11 #include "native_client/src/include/portability.h"
12 
13 #include <errno.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <time.h>
17 
18 #include "native_client/src/include/nacl_compiler_annotations.h"
19 #include "native_client/src/shared/platform/nacl_exit.h"
20 #include "native_client/src/shared/platform/nacl_log.h"
21 #include "native_client/src/trusted/service_runtime/nacl_globals.h"
22 #include "native_client/src/trusted/service_runtime/nacl_config.h"
23 #include "native_client/src/trusted/service_runtime/nacl_copy.h"
24 #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h"
25 #include "native_client/src/trusted/service_runtime/nacl_syscall_handlers.h"
26 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
27 #include "native_client/src/trusted/service_runtime/sel_rt.h"
28 
29 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
30 #include "native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h"
31 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
32 #include "native_client/src/trusted/service_runtime/nacl_stack_safety.h"
33 
34 
35 /*
36  * HandleStackContext() fetches some of the inputs to the NaCl syscall
37  * from the untrusted stack.  It updates NaClThreadContext so that the
38  * saved state will be complete in case this state is read via the
39  * thread suspension API.
40  *
41  * This is called while natp->suspend_state is set to
42  * NACL_APP_THREAD_UNTRUSTED, which has two consequences:
43  *
44  *  1) We may read untrusted address space without calling
45  *     NaClCopyTakeLock() first, because this function's execution
46  *     will be suspended while any mmap hole is opened up on Windows.
47  *
48  *  2) We may not claim any locks.  This means we may not call
49  *     NaClLog().  (An exception is that LOG_FATAL calls to NaClLog()
50  *     should be okay for internal errors.)
51  */
HandleStackContext(struct NaClAppThread * natp,uint32_t * tramp_ret_out,uintptr_t * sp_user_out)52 static void HandleStackContext(struct NaClAppThread *natp,
53                                uint32_t             *tramp_ret_out,
54                                uintptr_t            *sp_user_out) {
55   struct NaClApp *nap = natp->nap;
56   uintptr_t      sp_user;
57   uintptr_t      sp_sys;
58   uint32_t       tramp_ret;
59   nacl_reg_t     user_ret;
60 
61   /*
62    * sp_sys points to the top of the user stack where return addresses
63    * and syscall arguments are stored.
64    *
65    * Note that on x86-64, NaClUserToSysStackAddr() and
66    * NaClSysToUserStackAddr() do no range check.  sp_user must be okay
67    * for control to have reached here, because nacl_syscall*.S writes
68    * to the stack.
69    */
70   sp_user = NaClGetThreadCtxSp(&natp->user);
71   sp_sys = NaClUserToSysStackAddr(nap, sp_user);
72   /*
73    * Get the trampoline return address.  This just tells us which
74    * trampoline was called (and hence the syscall number); we never
75    * return to the trampoline.
76    */
77   tramp_ret = *(volatile uint32_t *) (sp_sys + NACL_TRAMPRET_FIX);
78   /*
79    * Get the user return address (where we return to after the system
80    * call).  We must ensure the address is properly sandboxed before
81    * switching back to untrusted code.
82    */
83   user_ret = *(volatile uintptr_t *) (sp_sys + NACL_USERRET_FIX);
84   user_ret = (nacl_reg_t) NaClSandboxCodeAddr(nap, (uintptr_t) user_ret);
85   natp->user.new_prog_ctr = user_ret;
86 
87   *tramp_ret_out = tramp_ret;
88   *sp_user_out = sp_user;
89 }
90 
NaClSyscallCSegHook(struct NaClThreadContext * ntcp)91 struct NaClThreadContext *NaClSyscallCSegHook(struct NaClThreadContext *ntcp) {
92   struct NaClAppThread      *natp = NaClAppThreadFromThreadContext(ntcp);
93   struct NaClApp            *nap;
94   uint32_t                  tramp_ret;
95   size_t                    sysnum;
96   uintptr_t                 sp_user;
97   uint32_t                  sysret;
98 
99   /*
100    * Mark the thread as running on a trusted stack as soon as possible
101    * so that we can report any crashes that occur after this point.
102    */
103   NaClStackSafetyNowOnTrustedStack();
104 
105   HandleStackContext(natp, &tramp_ret, &sp_user);
106 
107   /*
108    * Before this call, the thread could be suspended, so we should not
109    * lock any mutexes before this, otherwise it could cause a
110    * deadlock.
111    */
112   NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_UNTRUSTED,
113                                NACL_APP_THREAD_TRUSTED);
114 
115   nap = natp->nap;
116 
117   NaClCopyTakeLock(nap);
118   /*
119    * held until syscall args are copied, which occurs in the generated
120    * code.
121    */
122 
123   sysnum = (tramp_ret - NACL_SYSCALL_START_ADDR) >> NACL_SYSCALL_BLOCK_SHIFT;
124 
125   NaClLog(4, "Entering syscall %"NACL_PRIuS
126           ": return address 0x%08"NACL_PRIxNACL_REG"\n",
127           sysnum, natp->user.new_prog_ctr);
128 
129   /*
130    * usr_syscall_args is used by Decoder functions in
131    * nacl_syscall_handlers.c which is automatically generated file and
132    * placed in the
133    * scons-out/.../gen/native_client/src/trusted/service_runtime/
134    * directory.  usr_syscall_args must point to the first argument of
135    * a system call. System call arguments are placed on the untrusted
136    * user stack.
137    *
138    * We save the user address for user syscall arguments fetching and
139    * for VM range locking.
140    */
141   natp->usr_syscall_args = NaClRawUserStackAddrNormalize(sp_user +
142                                                          NACL_SYSARGS_FIX);
143 
144   if (NACL_UNLIKELY(sysnum >= NACL_MAX_SYSCALLS)) {
145     NaClLog(2, "INVALID system call %"NACL_PRIuS"\n", sysnum);
146     sysret = (uint32_t) -NACL_ABI_EINVAL;
147     NaClCopyDropLock(nap);
148   } else {
149     sysret = (*(nap->syscall_table[sysnum].handler))(natp);
150     /* Implicitly drops lock */
151   }
152   NaClLog(4,
153           ("Returning from syscall %"NACL_PRIuS": return value %"NACL_PRId32
154            " (0x%"NACL_PRIx32")\n"),
155           sysnum, sysret, sysret);
156   natp->user.sysret = sysret;
157 
158   /*
159    * After this NaClAppThreadSetSuspendState() call, we should not
160    * claim any mutexes, otherwise we risk deadlock.
161    */
162   NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_TRUSTED,
163                                NACL_APP_THREAD_UNTRUSTED);
164   NaClStackSafetyNowOnUntrustedStack();
165 
166   /*
167    * The caller switches back to untrusted code after this return.
168    */
169   return ntcp;
170 }
171