1 : /*
2 : * Copyright (c) 2011 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/shared/platform/nacl_exit.h"
19 : #include "native_client/src/shared/platform/nacl_log.h"
20 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
21 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
22 : #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h"
23 : #include "native_client/src/trusted/service_runtime/nacl_syscall_handlers.h"
24 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
25 : #include "native_client/src/trusted/service_runtime/sel_rt.h"
26 :
27 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
28 : #include "native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h"
29 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
30 : #include "native_client/src/trusted/service_runtime/nacl_stack_safety.h"
31 :
32 : int NaClArtificialDelay = -1;
33 :
34 :
35 : /*
36 : * The first syscall is from the NaCl module's main thread, and there
37 : * are no other user threads yet, so NACLDELAY check and the NACLCLOCK
38 : * usages are okay; when the NaCl module is multithreaded, the
39 : * variables they initialize are read-only.
40 : */
41 :
42 :
43 0 : void NaClMicroSleep(int microseconds) {
44 : static int initialized = 0;
45 : static tick_t cpu_clock = 0;
46 : tick_t now;
47 : tick_t end;
48 :
49 0 : if (!initialized) {
50 0 : char *env = getenv("NACLCLOCK");
51 0 : if (NULL != env) {
52 0 : cpu_clock = strtoul(env, (char **) NULL, 0);
53 : }
54 :
55 0 : initialized = 1;
56 : }
57 :
58 0 : now = get_ticks();
59 0 : end = now + (cpu_clock * microseconds) / 1000000;
60 0 : NaClLog(5, "Now %"NACL_PRId64". Waiting until %"NACL_PRId64".\n", now, end);
61 0 : while (get_ticks() < end)
62 : ;
63 0 : }
64 :
65 562 : NORETURN void NaClSyscallCSegHook(int32_t tls_idx) {
66 : struct NaClAppThread *natp;
67 : struct NaClApp *nap;
68 : struct NaClThreadContext *user;
69 : uintptr_t tramp_ret;
70 : nacl_reg_t user_ret;
71 : size_t sysnum;
72 : uintptr_t sp_user;
73 : uintptr_t sp_sys;
74 :
75 : /*
76 : * Mark the thread as running on a trusted stack as soon as possible
77 : * so that we can report any crashes that occur after this point.
78 : */
79 562 : NaClStackSafetyNowOnTrustedStack();
80 :
81 562 : natp = nacl_thread[tls_idx];
82 :
83 : /*
84 : * Before this call, the thread could be suspended, so we should not
85 : * lock any mutexes before this, otherwise it could cause a
86 : * deadlock.
87 : */
88 562 : NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_UNTRUSTED,
89 : NACL_APP_THREAD_TRUSTED);
90 :
91 562 : nap = natp->nap;
92 562 : user = &natp->user;
93 562 : sp_user = NaClGetThreadCtxSp(user);
94 :
95 : /* sp must be okay for control to have gotten here */
96 : #if !BENCHMARK
97 562 : NaClLog(4, "Entered NaClSyscallCSegHook\n");
98 562 : NaClLog(4, "user sp %"NACL_PRIxPTR"\n", sp_user);
99 : #endif
100 :
101 : /*
102 : * on x86_32 user stack:
103 : * esp+0: retaddr from lcall
104 : * esp+4: code seg from lcall
105 : * esp+8: retaddr to user module
106 : * esp+c: ...
107 : *
108 : * on ARM user stack
109 : * sp+0: retaddr from trampoline slot
110 : * sp+4: retaddr to user module
111 : * sp+8: arg0 to system call
112 : * sp+c: arg1 to system call
113 : * sp+10: ....
114 : */
115 :
116 562 : sp_sys = NaClUserToSysStackAddr(nap, sp_user);
117 : /*
118 : * sp_sys points to the top of user stack where there is a retaddr to
119 : * trampoline slot
120 : */
121 562 : tramp_ret = *(uintptr_t *)sp_sys;
122 562 : tramp_ret = NaClUserToSysStackAddr(nap, tramp_ret);
123 :
124 562 : sysnum = (tramp_ret - (nap->mem_start + NACL_SYSCALL_START_ADDR))
125 : >> NACL_SYSCALL_BLOCK_SHIFT;
126 :
127 : #if !BENCHMARK
128 562 : NaClLog(4, "system call %"NACL_PRIuS"\n", sysnum);
129 : #endif
130 :
131 : /*
132 : * getting user return address (the address where we need to return after
133 : * system call) from the user stack. (see stack layout above)
134 : */
135 562 : user_ret = *(uintptr_t *) (sp_sys + NACL_USERRET_FIX);
136 : /*
137 : * Fix the user stack, throw away return addresses from the top of the stack.
138 : * After this fix, the first argument to a system call must be on the top of
139 : * the user stack (see user stack layout above)
140 : */
141 562 : sp_sys += NACL_SYSARGS_FIX;
142 562 : sp_user += NACL_SYSCALLRET_FIX;
143 562 : NaClSetThreadCtxSp(user, sp_user);
144 :
145 562 : if (sysnum >= NACL_MAX_SYSCALLS) {
146 0 : NaClLog(2, "INVALID system call %"NACL_PRIdS"\n", sysnum);
147 0 : natp->sysret = -NACL_ABI_EINVAL;
148 : } else {
149 : #if !BENCHMARK
150 562 : NaClLog(4, "making system call %"NACL_PRIdS", "
151 : "handler 0x%08"NACL_PRIxPTR"\n",
152 : sysnum, (uintptr_t) nap->syscall_table[sysnum].handler);
153 : #endif
154 : /*
155 : * syscall_args is used by Decoder functions in
156 : * nacl_syscall_handlers.c which is automatically generated file
157 : * and placed in the
158 : * scons-out/.../gen/native_client/src/trusted/service_runtime/
159 : * directory. syscall_args must point to the first argument of a
160 : * system call. System call arguments are placed on the untrusted
161 : * user stack.
162 : */
163 562 : natp->syscall_args = (uintptr_t *) sp_sys;
164 562 : natp->sysret = (*(nap->syscall_table[sysnum].handler))(natp);
165 : }
166 : #if !BENCHMARK
167 559 : NaClLog(4,
168 : ("returning from system call %"NACL_PRIdS", return value %"NACL_PRId32
169 : " (0x%"NACL_PRIx32")\n"),
170 : sysnum, natp->sysret, natp->sysret);
171 :
172 559 : NaClLog(4, "return target 0x%08"NACL_PRIxNACL_REG"\n", user_ret);
173 559 : NaClLog(4, "user sp %"NACL_PRIxPTR"\n", sp_user);
174 : #endif
175 559 : if (-1 == NaClArtificialDelay) {
176 3 : char *delay = getenv("NACLDELAY");
177 3 : if (NULL != delay) {
178 0 : NaClArtificialDelay = strtol(delay, (char **) NULL, 0);
179 0 : NaClLog(0, "ARTIFICIAL DELAY %d us\n", NaClArtificialDelay);
180 : } else {
181 3 : NaClArtificialDelay = 0;
182 : }
183 : }
184 559 : if (0 != NaClArtificialDelay) {
185 0 : NaClMicroSleep(NaClArtificialDelay);
186 : }
187 :
188 : /*
189 : * before switching back to user module, we need to make sure that the
190 : * user_ret is properly sandboxed.
191 : */
192 559 : user_ret = (nacl_reg_t) NaClSandboxCodeAddr(nap, (uintptr_t)user_ret);
193 : /*
194 : * After this NaClAppThreadSetSuspendState() call, we should not
195 : * claim any mutexes, otherwise we risk deadlock. Note that if
196 : * NACLVERBOSITY is set high enough to enable the NaClLog() calls in
197 : * NaClSwitchToApp(), these calls could deadlock on Windows.
198 : */
199 559 : NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_TRUSTED,
200 : NACL_APP_THREAD_UNTRUSTED);
201 559 : NaClStackSafetyNowOnUntrustedStack();
202 :
203 559 : NaClSwitchToApp(natp, user_ret);
204 : /* NOTREACHED */
205 :
206 : fprintf(stderr, "NORETURN NaClSwitchToApp returned!?!\n");
207 : NaClAbort();
208 : }
|