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 : */
52 3538668 : static void HandleStackContext(struct NaClAppThread *natp,
53 3538668 : uint32_t *tramp_ret_out,
54 3538668 : uintptr_t *sp_user_out) {
55 3538668 : struct NaClApp *nap = natp->nap;
56 3538668 : uintptr_t sp_user;
57 3538668 : uintptr_t sp_sys;
58 3538668 : uint32_t tramp_ret;
59 3538668 : 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 3538668 : sp_user = NaClGetThreadCtxSp(&natp->user);
71 3538668 : 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 3538668 : 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 3538668 : user_ret = *(volatile uintptr_t *) (sp_sys + NACL_USERRET_FIX);
84 3538668 : user_ret = (nacl_reg_t) NaClSandboxCodeAddr(nap, (uintptr_t) user_ret);
85 3538668 : natp->user.new_prog_ctr = user_ret;
86 :
87 3538668 : *tramp_ret_out = tramp_ret;
88 3538668 : *sp_user_out = sp_user;
89 3538668 : }
90 :
91 3538669 : struct NaClThreadContext *NaClSyscallCSegHook(struct NaClThreadContext *ntcp) {
92 3538669 : struct NaClAppThread *natp = NaClAppThreadFromThreadContext(ntcp);
93 3538669 : struct NaClApp *nap;
94 3538669 : uint32_t tramp_ret;
95 3538669 : size_t sysnum;
96 3538669 : uintptr_t sp_user;
97 3538669 : 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 3538669 : NaClStackSafetyNowOnTrustedStack();
104 :
105 3538669 : 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 3538669 : NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_UNTRUSTED,
113 : NACL_APP_THREAD_TRUSTED);
114 :
115 3538669 : nap = natp->nap;
116 :
117 3538669 : NaClCopyTakeLock(nap);
118 : /*
119 : * held until syscall args are copied, which occurs in the generated
120 : * code.
121 : */
122 :
123 3538669 : sysnum = (tramp_ret - NACL_SYSCALL_START_ADDR) >> NACL_SYSCALL_BLOCK_SHIFT;
124 :
125 3538669 : 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 3538669 : natp->usr_syscall_args = NaClRawUserStackAddrNormalize(sp_user +
142 : NACL_SYSARGS_FIX);
143 :
144 3538669 : if (NACL_UNLIKELY(sysnum >= NACL_MAX_SYSCALLS)) {
145 0 : NaClLog(2, "INVALID system call %"NACL_PRIuS"\n", sysnum);
146 0 : sysret = -NACL_ABI_EINVAL;
147 0 : NaClCopyDropLock(nap);
148 0 : } else {
149 3538669 : sysret = (*(nap->syscall_table[sysnum].handler))(natp);
150 : /* Implicitly drops lock */
151 : }
152 3517806 : NaClLog(4,
153 : ("Returning from syscall %"NACL_PRIuS": return value %"NACL_PRId32
154 : " (0x%"NACL_PRIx32")\n"),
155 : sysnum, sysret, sysret);
156 3517806 : natp->user.sysret = sysret;
157 :
158 : /*
159 : * After this NaClAppThreadSetSuspendState() call, we should not
160 : * claim any mutexes, otherwise we risk deadlock.
161 : */
162 3517806 : NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_TRUSTED,
163 : NACL_APP_THREAD_UNTRUSTED);
164 3517806 : NaClStackSafetyNowOnUntrustedStack();
165 :
166 : /*
167 : * The caller switches back to untrusted code after this return.
168 : */
169 3517806 : return ntcp;
170 : }
|