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 <errno.h>
8 : #include <signal.h>
9 : #include <string.h>
10 : #include <sys/mman.h>
11 : #include <unistd.h>
12 :
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/arch/sel_ldr_arch.h"
17 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
18 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
19 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
20 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
21 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
22 : #include "native_client/src/trusted/service_runtime/sel_rt.h"
23 :
24 :
25 : struct ExceptionFrame {
26 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
27 : nacl_reg_t return_addr;
28 : # if NACL_BUILD_SUBARCH == 32
29 : uint32_t prog_ctr; /* Function argument 1 */
30 : uint32_t stack_ptr; /* Function argument 2 */
31 : # endif
32 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
33 : /*
34 : * Empty structs are a corner case and can have different sizeof()s
35 : * in C and C++, so to avoid potential confusion we have a dummy
36 : * entry here.
37 : * TODO(mseaborn): Eventually we will push a proper stack frame
38 : * containing a full register dump, so this dummy field will go
39 : * away.
40 : */
41 : uint32_t dummy;
42 : #else
43 : # error Unknown architecture
44 : #endif
45 : };
46 :
47 : /*
48 : * This module is based on the Posix signal model. See:
49 : * http://www.opengroup.org/onlinepubs/009695399/functions/sigaction.html
50 : */
51 :
52 : #ifndef MAP_ANONYMOUS
53 : #define MAP_ANONYMOUS MAP_ANON
54 : #endif
55 :
56 : /*
57 : * TODO(noelallen) split these macros and conditional compiles
58 : * into architecture specific files. Bug #955
59 : */
60 :
61 : /* Use 4K more than the minimum to allow breakpad to run. */
62 : #define SIGNAL_STACK_SIZE (SIGSTKSZ + 4096)
63 : #define STACK_GUARD_SIZE NACL_PAGESIZE
64 :
65 : #ifdef SIGSTKFLT
66 : #define SIGNAL_COUNT 8
67 : static int s_Signals[SIGNAL_COUNT] = {
68 : SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV, SIGSTKFLT
69 : };
70 : #else
71 : #define SIGNAL_COUNT 7
72 : static int s_Signals[SIGNAL_COUNT] = {
73 : SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV
74 : };
75 : #endif
76 :
77 : static struct sigaction s_OldActions[SIGNAL_COUNT];
78 :
79 3 : int NaClSignalStackAllocate(void **result) {
80 : /*
81 : * We use mmap() to allocate the signal stack for two reasons:
82 : *
83 : * 1) By page-aligning the memory allocation (which malloc() does
84 : * not do for small allocations), we avoid allocating any real
85 : * memory in the common case in which the signal handler is never
86 : * run.
87 : *
88 : * 2) We get to create a guard page, to guard against the unlikely
89 : * occurrence of the signal handler both overrunning and doing so in
90 : * an exploitable way.
91 : */
92 : uint8_t *stack = mmap(NULL, SIGNAL_STACK_SIZE + STACK_GUARD_SIZE,
93 : PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
94 3 : -1, 0);
95 3 : if (stack == MAP_FAILED) {
96 0 : return 0;
97 : }
98 : /* We assume that the stack grows downwards. */
99 3 : if (mprotect(stack, STACK_GUARD_SIZE, PROT_NONE) != 0) {
100 0 : NaClLog(LOG_FATAL, "Failed to mprotect() the stack guard page:\n\t%s\n",
101 : strerror(errno));
102 : }
103 3 : *result = stack;
104 3 : return 1;
105 : }
106 :
107 3 : void NaClSignalStackFree(void *stack) {
108 3 : CHECK(stack != NULL);
109 3 : if (munmap(stack, SIGNAL_STACK_SIZE + STACK_GUARD_SIZE) != 0) {
110 0 : NaClLog(LOG_FATAL, "Failed to munmap() signal stack:\n\t%s\n",
111 : strerror(errno));
112 : }
113 3 : }
114 :
115 3 : void NaClSignalStackRegister(void *stack) {
116 : /*
117 : * If we set up signal handlers, we must ensure that any thread that
118 : * runs untrusted code has an alternate signal stack set up. The
119 : * default for a new thread is to use the stack pointer from the
120 : * point at which the fault occurs, but it would not be safe to use
121 : * untrusted code's %esp/%rsp value.
122 : */
123 : stack_t st;
124 3 : st.ss_size = SIGNAL_STACK_SIZE;
125 3 : st.ss_sp = ((uint8_t *) stack) + STACK_GUARD_SIZE;
126 3 : st.ss_flags = 0;
127 3 : if (sigaltstack(&st, NULL) != 0) {
128 0 : NaClLog(LOG_FATAL, "Failed to register signal stack:\n\t%s\n",
129 : strerror(errno));
130 : }
131 3 : }
132 :
133 3 : void NaClSignalStackUnregister(void) {
134 : /*
135 : * Unregister the signal stack in case a fault occurs between the
136 : * thread deallocating the signal stack and exiting. Such a fault
137 : * could be unsafe if the address space were reallocated before the
138 : * fault, although that is unlikely.
139 : */
140 : stack_t st;
141 : #if NACL_OSX
142 : /*
143 : * This is a workaround for a bug in Mac OS X's libc, in which new
144 : * versions of the sigaltstack() wrapper return ENOMEM if ss_size is
145 : * less than MINSIGSTKSZ, even when ss_size should be ignored
146 : * because we are unregistering the signal stack.
147 : * See http://code.google.com/p/nativeclient/issues/detail?id=1053
148 : */
149 3 : st.ss_size = MINSIGSTKSZ;
150 : #else
151 : st.ss_size = 0;
152 : #endif
153 3 : st.ss_sp = NULL;
154 3 : st.ss_flags = SS_DISABLE;
155 3 : if (sigaltstack(&st, NULL) != 0) {
156 0 : NaClLog(LOG_FATAL, "Failed to unregister signal stack:\n\t%s\n",
157 : strerror(errno));
158 : }
159 3 : }
160 :
161 2 : static void FindAndRunHandler(int sig, siginfo_t *info, void *uc) {
162 2 : if (NaClSignalHandlerFind(sig, uc) == NACL_SIGNAL_SEARCH) {
163 : int a;
164 :
165 : /* If we need to keep searching, try the old signal handler. */
166 0 : for (a = 0; a < SIGNAL_COUNT; a++) {
167 : /* If we handle this signal */
168 0 : if (s_Signals[a] == sig) {
169 : /* If this is a real sigaction pointer... */
170 0 : if (s_OldActions[a].sa_flags & SA_SIGINFO) {
171 : /* then call the old handler. */
172 0 : s_OldActions[a].sa_sigaction(sig, info, uc);
173 0 : break;
174 : }
175 : /* otherwise check if it is a real signal pointer */
176 0 : if ((s_OldActions[a].sa_handler != SIG_DFL) &&
177 : (s_OldActions[a].sa_handler != SIG_IGN)) {
178 : /* and call the old signal. */
179 0 : s_OldActions[a].sa_handler(sig);
180 0 : break;
181 : }
182 : /*
183 : * We matched the signal, but didn't handle it, so we emulate
184 : * the default behavior which is to exit the app with the signal
185 : * number as the error code.
186 : */
187 0 : NaClSignalErrorMessage("Failed to handle signal.\n");
188 0 : NaClExit(-sig);
189 : }
190 : }
191 : }
192 0 : }
193 :
194 : /*
195 : * This function checks whether we can dispatch the signal to an
196 : * untrusted exception handler. If we can, it modifies the register
197 : * state to call the handler and writes a stack frame into into
198 : * untrusted address space, and returns true. Otherwise, it returns
199 : * false.
200 : */
201 : static int DispatchToUntrustedHandler(struct NaClAppThread *natp,
202 0 : struct NaClSignalContext *regs) {
203 0 : struct NaClApp *nap = natp->nap;
204 : uintptr_t frame_addr;
205 : volatile struct ExceptionFrame *frame;
206 : uint32_t new_stack_ptr;
207 : /*
208 : * Returning from the exception handler is not possible, so to avoid
209 : * any confusion that might arise from jumping to an uninitialised
210 : * address, we set the return address to zero.
211 : */
212 0 : const uint32_t kReturnAddr = 0;
213 :
214 0 : if (nap->exception_handler == 0) {
215 0 : return 0;
216 : }
217 0 : if (natp->user.exception_flag) {
218 0 : return 0;
219 : }
220 :
221 0 : natp->user.exception_flag = 1;
222 :
223 0 : if (natp->user.exception_stack == 0) {
224 0 : new_stack_ptr = regs->stack_ptr - NACL_STACK_RED_ZONE;
225 : } else {
226 0 : new_stack_ptr = natp->user.exception_stack;
227 : }
228 : /* Allocate space for the stack frame, and ensure its alignment. */
229 0 : new_stack_ptr -= sizeof(struct ExceptionFrame) - NACL_STACK_PAD_BELOW_ALIGN;
230 0 : new_stack_ptr = new_stack_ptr & ~NACL_STACK_ALIGN_MASK;
231 0 : new_stack_ptr -= NACL_STACK_PAD_BELOW_ALIGN;
232 0 : frame_addr = NaClUserToSysAddrRange(nap, new_stack_ptr,
233 : sizeof(struct ExceptionFrame));
234 0 : if (frame_addr == kNaClBadAddress) {
235 : /* We cannot write the stack frame. */
236 0 : return 0;
237 : }
238 0 : frame = (struct ExceptionFrame *) frame_addr;
239 :
240 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
241 0 : frame->return_addr = kReturnAddr;
242 0 : regs->flags &= ~NACL_X86_DIRECTION_FLAG;
243 : #endif
244 :
245 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
246 0 : frame->prog_ctr = regs->prog_ctr; /* Argument 1 */
247 0 : frame->stack_ptr = regs->stack_ptr; /* Argument 2 */
248 :
249 0 : regs->prog_ctr = nap->exception_handler;
250 0 : regs->stack_ptr = new_stack_ptr;
251 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
252 : /* Truncate the saved %rsp and %rbp values for portability. */
253 : regs->rdi = (uint32_t) regs->prog_ctr; /* Argument 1 */
254 : regs->rsi = (uint32_t) regs->stack_ptr; /* Argument 2 */
255 :
256 : regs->prog_ctr = NaClUserToSys(nap, nap->exception_handler);
257 : regs->stack_ptr = NaClUserToSys(nap, new_stack_ptr);
258 : /*
259 : * We cannot leave %rbp unmodified because the x86-64 sandbox allows
260 : * %rbp to point temporarily to the lower 4GB of address space, and
261 : * we could have received an asynchronous signal while %rbp is in
262 : * this state. Even SIGSEGV can be asynchronous if sent with
263 : * kill().
264 : *
265 : * For now, reset %rbp to zero in untrusted address space. In the
266 : * future, we might want to allow the stack to be unwound past the
267 : * exception frame, and so we might want to treat %rbp differently.
268 : */
269 : regs->rbp = nap->mem_start;
270 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
271 : /*
272 : * We write to memory here to get consistent behaviour for
273 : * unwritable stacks across architectures, to simplify testing.
274 : * TODO(mseaborn): This will eventually be replaced with writing a
275 : * register dump to the stack frame.
276 : */
277 : frame->dummy = 0;
278 :
279 : regs->lr = kReturnAddr;
280 :
281 : regs->r0 = regs->prog_ctr; /* Argument 1 */
282 : regs->r1 = regs->stack_ptr; /* Argument 2 */
283 :
284 : regs->prog_ctr = NaClUserToSys(nap, nap->exception_handler);
285 : regs->stack_ptr = NaClUserToSys(nap, new_stack_ptr);
286 : #else
287 : # error Unsupported architecture
288 : #endif
289 :
290 0 : return 1;
291 : }
292 :
293 2 : static void SignalCatch(int sig, siginfo_t *info, void *uc) {
294 : struct NaClSignalContext sigCtx;
295 : int is_untrusted;
296 : struct NaClAppThread *natp;
297 :
298 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
299 : /*
300 : * Reset the x86 direction flag. New versions of gcc and libc
301 : * assume that the direction flag is clear on entry to a function,
302 : * as the x86 ABI requires. However, untrusted code can set this
303 : * flag, and versions of Linux before 2.6.25 do not clear the flag
304 : * before running the signal handler, so we clear it here for safety.
305 : * See http://code.google.com/p/nativeclient/issues/detail?id=1495
306 : */
307 2 : __asm__("cld");
308 : #endif
309 :
310 2 : NaClSignalContextFromHandler(&sigCtx, uc);
311 2 : NaClSignalContextGetCurrentThread(&sigCtx, &is_untrusted, &natp);
312 :
313 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
314 2 : if (is_untrusted) {
315 : /*
316 : * On Linux, the kernel does not restore %gs when entering the
317 : * signal handler, so we must do that here. We need to do this
318 : * for glibc's TLS to work. Some builds of glibc fetch a syscall
319 : * function pointer from glibc's static TLS area. If we failed to
320 : * restore %gs, this function pointer would be under the control
321 : * of untrusted code, and we would have a vulnerability.
322 : *
323 : * Note that, in comparison, Breakpad tries to avoid using libc
324 : * calls at all when a crash occurs.
325 : *
326 : * On Mac OS X, the kernel *does* restore the original %gs when
327 : * entering the signal handler. Our assignment to %gs here is
328 : * therefore not strictly necessary, but not harmful. However,
329 : * this does mean we need to check the original %gs value (from
330 : * the signal frame) rather than the current %gs value (from
331 : * NaClGetGs()).
332 : *
333 : * Both systems necessarily restore %cs, %ds, and %ss otherwise
334 : * we would have a hard time handling signals in untrusted code
335 : * at all.
336 : */
337 0 : NaClSetGs(natp->sys.gs);
338 : }
339 : #endif
340 :
341 2 : if (is_untrusted && sig == SIGSEGV) {
342 0 : if (DispatchToUntrustedHandler(natp, &sigCtx)) {
343 0 : NaClSignalContextToHandler(uc, &sigCtx);
344 : /* Resume untrusted code using the modified register state. */
345 0 : return;
346 : }
347 : }
348 :
349 2 : FindAndRunHandler(sig, info, uc);
350 : }
351 :
352 :
353 14 : void NaClSignalHandlerInitPlatform() {
354 : struct sigaction sa;
355 : int a;
356 :
357 14 : memset(&sa, 0, sizeof(sa));
358 14 : sigemptyset(&sa.sa_mask);
359 14 : sa.sa_sigaction = SignalCatch;
360 14 : sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
361 :
362 : /* Mask all exceptions we catch to prevent re-entry */
363 112 : for (a = 0; a < SIGNAL_COUNT; a++) {
364 98 : sigaddset(&sa.sa_mask, s_Signals[a]);
365 : }
366 :
367 : /* Install all handlers */
368 112 : for (a = 0; a < SIGNAL_COUNT; a++) {
369 98 : if (sigaction(s_Signals[a], &sa, &s_OldActions[a]) != 0) {
370 0 : NaClLog(LOG_FATAL, "Failed to install handler for %d.\n\tERR:%s\n",
371 : s_Signals[a], strerror(errno));
372 : }
373 : }
374 14 : }
375 :
376 12 : void NaClSignalHandlerFiniPlatform() {
377 : int a;
378 :
379 : /* Remove all handlers */
380 96 : for (a = 0; a < SIGNAL_COUNT; a++) {
381 84 : if (sigaction(s_Signals[a], &s_OldActions[a], NULL) != 0) {
382 0 : NaClLog(LOG_FATAL, "Failed to unregister handler for %d.\n\tERR:%s\n",
383 : s_Signals[a], strerror(errno));
384 : }
385 : }
386 12 : }
387 :
388 : /*
389 : * Check that signal handlers are not registered. We want to
390 : * discourage Chrome or libraries from registering signal handlers
391 : * themselves, because those signal handlers are often not safe when
392 : * triggered from untrusted code. For background, see:
393 : * http://code.google.com/p/nativeclient/issues/detail?id=1607
394 : */
395 12 : void NaClSignalAssertNoHandlers() {
396 : int index;
397 96 : for (index = 0; index < SIGNAL_COUNT; index++) {
398 84 : int signum = s_Signals[index];
399 : struct sigaction sa;
400 84 : if (sigaction(signum, NULL, &sa) != 0) {
401 0 : NaClLog(LOG_FATAL, "NaClSignalAssertNoHandlers: "
402 : "sigaction() call failed\n");
403 : }
404 84 : if ((sa.sa_flags & SA_SIGINFO) != 0
405 : ? sa.sa_sigaction != NULL
406 : : (sa.sa_handler != SIG_DFL && sa.sa_handler != SIG_IGN)) {
407 0 : NaClLog(LOG_FATAL, "NaClSignalAssertNoHandlers: "
408 : "A signal handler is registered for signal %d. "
409 : "Did Breakpad register this?\n", signum);
410 : }
411 : }
412 12 : }
|