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 : #include <stdio.h>
8 : #include <stdlib.h>
9 : #include <string.h>
10 :
11 : #include "native_client/src/include/nacl_base.h"
12 : #include "native_client/src/include/portability_io.h"
13 : #include "native_client/src/shared/platform/nacl_check.h"
14 : #include "native_client/src/shared/platform/nacl_exit.h"
15 : #include "native_client/src/shared/platform/nacl_log.h"
16 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
17 : #include "native_client/src/trusted/service_runtime/nacl_exception.h"
18 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
19 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
20 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
21 :
22 : #if NACL_WINDOWS
23 : #include <io.h>
24 : #define write _write
25 : #else
26 : #include <unistd.h>
27 : #endif
28 :
29 :
30 0 : ssize_t NaClSignalErrorMessage(const char *msg) {
31 : /*
32 : * We cannot use NaClLog() in the context of a signal handler: it is
33 : * too complex. However, write() is signal-safe.
34 : */
35 0 : size_t len_t = strlen(msg);
36 0 : int len = (int) len_t;
37 :
38 : /*
39 : * Write uses int not size_t, so we may wrap the length and/or
40 : * generate a negative value. Only print if it matches.
41 : */
42 0 : if ((len > 0) && (len_t == (size_t) len)) {
43 0 : return (ssize_t) write(2, msg, len);
44 : }
45 :
46 0 : return 0;
47 0 : }
48 :
49 : /*
50 : * This function takes the register state (sig_ctx) for a thread
51 : * (natp) that has been suspended and returns whether the thread was
52 : * suspended while executing untrusted code.
53 : */
54 11674 : int NaClSignalContextIsUntrusted(struct NaClAppThread *natp,
55 11674 : const struct NaClSignalContext *sig_ctx) {
56 11674 : uint32_t prog_ctr;
57 :
58 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
59 : /*
60 : * Note that we do not check "sig_ctx != NaClGetGlobalCs()". On Mac
61 : * OS X, if a thread is suspended while in a syscall,
62 : * thread_get_state() returns cs=0x7 rather than cs=0x17 (the normal
63 : * cs value for trusted code).
64 : */
65 : if (sig_ctx->cs != natp->user.cs)
66 : return 0;
67 : #elif (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64) || \
68 : NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm || \
69 : NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
70 11674 : if (!NaClIsUserAddr(natp->nap, sig_ctx->prog_ctr))
71 11498 : return 0;
72 : #else
73 : # error Unsupported architecture
74 : #endif
75 :
76 176 : prog_ctr = (uint32_t) sig_ctx->prog_ctr;
77 528 : return (prog_ctr < NACL_TRAMPOLINE_START ||
78 : prog_ctr >= NACL_TRAMPOLINE_END);
79 11674 : }
80 :
81 : /*
82 : * Sanity checks: Reject unsafe register state that untrusted code
83 : * should not be able to set unless there is a sandbox hole. We do
84 : * this in an attempt to prevent such a hole from being exploitable.
85 : */
86 14923 : int NaClSignalCheckSandboxInvariants(const struct NaClSignalContext *regs,
87 14923 : struct NaClAppThread *natp) {
88 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
89 : if (regs->cs != natp->user.cs ||
90 : regs->ds != natp->user.ds ||
91 : regs->es != natp->user.es ||
92 : regs->fs != natp->user.fs ||
93 : regs->gs != natp->user.gs ||
94 : regs->ss != natp->user.ss) {
95 : return 0;
96 : }
97 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
98 : /*
99 : * Untrusted code can temporarily set %rsp/%rbp to be in the 0..4GB
100 : * range but it should not be able to generate a fault while in that
101 : * state.
102 : */
103 14923 : if (regs->r15 != natp->user.r15 ||
104 14923 : !NaClIsUserAddr(natp->nap, regs->stack_ptr) ||
105 14923 : !NaClIsUserAddr(natp->nap, regs->rbp)) {
106 0 : return 0;
107 : }
108 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
109 : if (!NaClIsUserAddr(natp->nap, regs->stack_ptr) ||
110 : regs->r9 != (uintptr_t) &natp->user.tls_value1) {
111 : return 0;
112 : }
113 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
114 : if (!NaClIsUserAddr(natp->nap, regs->stack_ptr) ||
115 : regs->t6 != NACL_CONTROL_FLOW_MASK ||
116 : regs->t7 != NACL_DATA_FLOW_MASK) {
117 : return 0;
118 : }
119 : #else
120 : # error Unsupported architecture
121 : #endif
122 14923 : return 1;
123 14923 : }
124 :
125 0 : void NaClSignalHandleUntrusted(int signal,
126 0 : const struct NaClSignalContext *regs,
127 0 : int is_untrusted) {
128 0 : char tmp[128];
129 : /*
130 : * Return an 8 bit error code which is -signal to
131 : * simulate normal OS behavior
132 : */
133 0 : if (is_untrusted) {
134 0 : SNPRINTF(tmp, sizeof(tmp), "\n** Signal %d from untrusted code: "
135 : "pc=%" NACL_PRIxNACL_REG "\n", signal, regs->prog_ctr);
136 0 : NaClSignalErrorMessage(tmp);
137 0 : NaClExit((-signal) & 0xFF);
138 0 : } else {
139 0 : SNPRINTF(tmp, sizeof(tmp), "\n** Signal %d from trusted code: "
140 : "pc=%" NACL_PRIxNACL_REG "\n", signal, regs->prog_ctr);
141 0 : NaClSignalErrorMessage(tmp);
142 : /*
143 : * Continue the search for another handler so that trusted crashes
144 : * can be handled by the Breakpad crash reporter.
145 : */
146 : }
147 0 : }
148 :
149 :
150 : /*
151 : * This is a separate function to make it obvious from the crash
152 : * reports that this crash is deliberate and for testing purposes.
153 : */
154 : void NaClSignalTestCrashOnStartup(void) {
155 265 : if (getenv("NACL_CRASH_TEST") != NULL) {
156 0 : NaClSignalErrorMessage("[CRASH_TEST] Causing crash in NaCl "
157 : "trusted code...\n");
158 : /*
159 : * Clang transmutes a NULL pointer reference into a generic
160 : * "undefined" case. That code crashes with a different signal
161 : * than an actual bad pointer reference, violating the tests'
162 : * expectations. A pointer that is known bad but is not literally
163 : * NULL does not get this treatment.
164 : */
165 0 : *(volatile int *) 1 = 0;
166 0 : }
167 265 : }
168 :
169 : static void NaClUserRegisterStateFromSignalContext(
170 14923 : volatile NaClUserRegisterState *dest,
171 14923 : const struct NaClSignalContext *src) {
172 : #define COPY_REG(reg) dest->reg = src->reg
173 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
174 : COPY_REG(eax);
175 : COPY_REG(ecx);
176 : COPY_REG(edx);
177 : COPY_REG(ebx);
178 : COPY_REG(stack_ptr);
179 : COPY_REG(ebp);
180 : COPY_REG(esi);
181 : COPY_REG(edi);
182 : COPY_REG(prog_ctr);
183 : COPY_REG(flags);
184 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
185 14923 : COPY_REG(rax);
186 14923 : COPY_REG(rcx);
187 14923 : COPY_REG(rdx);
188 14923 : COPY_REG(rbx);
189 14923 : COPY_REG(stack_ptr);
190 14923 : COPY_REG(rbp);
191 14923 : COPY_REG(rsi);
192 14923 : COPY_REG(rdi);
193 14923 : COPY_REG(r8);
194 14923 : COPY_REG(r9);
195 14923 : COPY_REG(r10);
196 14923 : COPY_REG(r11);
197 14923 : COPY_REG(r12);
198 14923 : COPY_REG(r13);
199 14923 : COPY_REG(r14);
200 14923 : COPY_REG(r15);
201 14923 : COPY_REG(prog_ctr);
202 14923 : COPY_REG(flags);
203 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
204 : COPY_REG(r0);
205 : COPY_REG(r1);
206 : COPY_REG(r2);
207 : COPY_REG(r3);
208 : COPY_REG(r4);
209 : COPY_REG(r5);
210 : COPY_REG(r6);
211 : COPY_REG(r7);
212 : COPY_REG(r8);
213 : /* Don't leak the address of NaClAppThread by reporting r9's value here. */
214 : dest->r9 = -1;
215 : COPY_REG(r10);
216 : COPY_REG(r11);
217 : COPY_REG(r12);
218 : COPY_REG(stack_ptr);
219 : COPY_REG(lr);
220 : COPY_REG(prog_ctr);
221 : COPY_REG(cpsr);
222 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
223 : COPY_REG(zero);
224 : COPY_REG(at);
225 : COPY_REG(v0);
226 : COPY_REG(v1);
227 : COPY_REG(a0);
228 : COPY_REG(a1);
229 : COPY_REG(a2);
230 : COPY_REG(a3);
231 : COPY_REG(t0);
232 : COPY_REG(t1);
233 : COPY_REG(t2);
234 : COPY_REG(t3);
235 : COPY_REG(t4);
236 : COPY_REG(t5);
237 : COPY_REG(t6);
238 : COPY_REG(t7);
239 : COPY_REG(s0);
240 : COPY_REG(s1);
241 : COPY_REG(s2);
242 : COPY_REG(s3);
243 : COPY_REG(s4);
244 : COPY_REG(s5);
245 : COPY_REG(s6);
246 : COPY_REG(s7);
247 : COPY_REG(t8);
248 : COPY_REG(t9);
249 : COPY_REG(k0);
250 : COPY_REG(k1);
251 : COPY_REG(global_ptr);
252 : COPY_REG(stack_ptr);
253 : COPY_REG(frame_ptr);
254 : COPY_REG(return_addr);
255 : COPY_REG(prog_ctr);
256 : #else
257 : # error Unsupported architecture
258 : #endif
259 : #undef COPY_REG
260 14923 : }
261 :
262 : /*
263 : * The |frame| argument is volatile because this function writes
264 : * directly into untrusted address space on Linux.
265 : */
266 14923 : void NaClSignalSetUpExceptionFrame(volatile struct NaClExceptionFrame *frame,
267 14923 : const struct NaClSignalContext *regs,
268 14923 : uint32_t context_user_addr) {
269 14923 : unsigned i;
270 :
271 : /*
272 : * Use the end of frame->portable for the size, avoiding padding
273 : * added after it within NaClExceptionFrame.
274 : */
275 14923 : frame->context.size =
276 : (uint32_t) ((uintptr_t) (&frame->portable + 1) -
277 : (uintptr_t) &frame->context);
278 14923 : frame->context.portable_context_offset =
279 : (uint32_t) ((uintptr_t) &frame->portable -
280 : (uintptr_t) &frame->context);
281 14923 : frame->context.portable_context_size = sizeof(frame->portable);
282 14923 : frame->context.arch = NACL_ELF_E_MACHINE;
283 14923 : frame->context.regs_size = sizeof(frame->context.regs);
284 :
285 : /* Avoid memset() here because |frame| is volatile. */
286 358152 : for (i = 0; i < NACL_ARRAY_SIZE(frame->context.reserved); i++) {
287 164153 : frame->context.reserved[i] = 0;
288 164153 : }
289 :
290 14923 : NaClUserRegisterStateFromSignalContext(&frame->context.regs, regs);
291 :
292 14923 : frame->portable.prog_ctr = (uint32_t) regs->prog_ctr;
293 14923 : frame->portable.stack_ptr = (uint32_t) regs->stack_ptr;
294 :
295 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
296 : frame->context_ptr = context_user_addr;
297 : frame->portable.frame_ptr = (uint32_t) regs->ebp;
298 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
299 29846 : UNREFERENCED_PARAMETER(context_user_addr);
300 14923 : frame->portable.frame_ptr = (uint32_t) regs->rbp;
301 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
302 : UNREFERENCED_PARAMETER(context_user_addr);
303 : frame->portable.frame_ptr = regs->r11;
304 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
305 : UNREFERENCED_PARAMETER(context_user_addr);
306 : frame->portable.frame_ptr = regs->frame_ptr;
307 : #else
308 : # error Unsupported architecture
309 : #endif
310 :
311 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
312 : /*
313 : * Returning from the exception handler is not possible, so to avoid
314 : * any confusion that might arise from jumping to an uninitialised
315 : * address, we set the return address to zero.
316 : */
317 14923 : frame->return_addr = 0;
318 : #endif
319 14923 : }
|