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 <stddef.h>
10 : #include <string.h>
11 :
12 : #include "native_client/src/include/nacl_macros.h"
13 : #include "native_client/src/include/portability_io.h"
14 : #include "native_client/src/shared/platform/nacl_check.h"
15 : #include "native_client/src/shared/platform/nacl_exit.h"
16 : #include "native_client/src/shared/platform/nacl_log.h"
17 : #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
18 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
19 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
20 : #include "native_client/src/trusted/service_runtime/nacl_exception.h"
21 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
22 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
23 : #include "native_client/src/trusted/service_runtime/nacl_tls.h"
24 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
25 : #include "native_client/src/trusted/service_runtime/sel_rt.h"
26 : #include "native_client/src/trusted/service_runtime/thread_suspension.h"
27 :
28 :
29 : /*
30 : * This module is based on the Posix signal model. See:
31 : * http://www.opengroup.org/onlinepubs/009695399/functions/sigaction.html
32 : */
33 :
34 : /*
35 : * The signals listed here should either be handled by NaCl (or otherwise
36 : * trusted) or have handlers that are expected to crash.
37 : * Signals for which handlers are expected to crash should be listed
38 : * in the NaClSignalHandleCustomCrashHandler function below.
39 : */
40 : static int s_Signals[] = {
41 : #if NACL_ARCH(NACL_BUILD_ARCH) != NACL_mips
42 : /* This signal does not exist on MIPS. */
43 : SIGSTKFLT,
44 : #endif
45 : SIGSYS, /* Used to support a seccomp-bpf sandbox. */
46 : NACL_THREAD_SUSPEND_SIGNAL,
47 : SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV,
48 : /* Handle SIGABRT in case someone sends it asynchronously using kill(). */
49 : SIGABRT
50 : };
51 :
52 : static struct sigaction s_OldActions[NACL_ARRAY_SIZE_UNSAFE(s_Signals)];
53 :
54 : static NaClSignalHandler g_handler_func;
55 :
56 2 : void NaClSignalHandlerSet(NaClSignalHandler func) {
57 2 : g_handler_func = func;
58 2 : }
59 :
60 : /*
61 : * Returns, via is_untrusted, whether the signal happened while
62 : * executing untrusted code.
63 : *
64 : * Returns, via result_thread, the NaClAppThread that untrusted code
65 : * was running in.
66 : *
67 : * Note that this should only be called from the thread in which the
68 : * signal occurred, because on x86-64 it reads a thread-local variable
69 : * (nacl_current_thread).
70 : */
71 140375 : static void GetCurrentThread(const struct NaClSignalContext *sig_ctx,
72 : int *is_untrusted,
73 : struct NaClAppThread **result_thread) {
74 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
75 : /*
76 : * For x86-32, if %cs does not match, it is untrusted code.
77 : *
78 : * Note that this check might not be valid on Mac OS X, because
79 : * thread_get_state() does not return the value of NaClGetGlobalCs()
80 : * for a thread suspended inside a syscall. However, this code is
81 : * not used on Mac OS X.
82 : */
83 140375 : *is_untrusted = (NaClGetGlobalCs() != sig_ctx->cs);
84 140375 : *result_thread = NaClAppThreadGetFromIndex(sig_ctx->gs >> 3);
85 : #elif (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64) || \
86 : NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm || \
87 : NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
88 : struct NaClAppThread *natp = NaClTlsGetCurrentThread();
89 : if (natp == NULL) {
90 : *is_untrusted = 0;
91 : *result_thread = NULL;
92 : } else {
93 : /*
94 : * Get the address of an arbitrary local, stack-allocated variable,
95 : * just for the purpose of doing a sanity check.
96 : */
97 : void *pointer_into_stack = &natp;
98 : /*
99 : * Sanity check: Make sure the stack we are running on is not
100 : * allocated in untrusted memory. This checks that the alternate
101 : * signal stack is correctly set up, because otherwise, if it is
102 : * not set up, the test case would not detect that.
103 : *
104 : * There is little point in doing a CHECK instead of a DCHECK,
105 : * because if we are running off an untrusted stack, we have already
106 : * lost.
107 : */
108 : DCHECK(!NaClIsUserAddr(natp->nap, (uintptr_t) pointer_into_stack));
109 : *is_untrusted = NaClIsUserAddr(natp->nap, sig_ctx->prog_ctr);
110 : *result_thread = natp;
111 : }
112 : #else
113 : # error Unsupported architecture
114 : #endif
115 :
116 : /*
117 : * Trusted code could accidentally jump into sandbox address space,
118 : * so don't rely on prog_ctr on its own for determining whether a
119 : * crash comes from untrusted code. We don't want to restore
120 : * control to an untrusted exception handler if trusted code
121 : * crashes.
122 : */
123 258985 : if (*is_untrusted &&
124 118610 : ((*result_thread)->suspend_state & NACL_APP_THREAD_UNTRUSTED) == 0) {
125 0 : *is_untrusted = 0;
126 : }
127 140375 : }
128 :
129 : /*
130 : * If |sig| had a handler that was expected to crash, exit.
131 : */
132 0 : static void NaClSignalHandleCustomCrashHandler(int sig) {
133 : /* Only SIGSYS is expected to have a custom crash handler. */
134 0 : if (sig == SIGSYS) {
135 : char tmp[128];
136 0 : SNPRINTF(tmp, sizeof(tmp),
137 : "\n** Signal %d has a custom crash handler but did not crash.\n",
138 : sig);
139 0 : NaClSignalErrorMessage(tmp);
140 0 : NaClExit(-sig);
141 : }
142 0 : }
143 :
144 2 : static void FindAndRunHandler(int sig, siginfo_t *info, void *uc) {
145 : unsigned int a;
146 :
147 : /* If we need to keep searching, try the old signal handler. */
148 20 : for (a = 0; a < NACL_ARRAY_SIZE(s_Signals); a++) {
149 : /* If we handle this signal */
150 20 : if (s_Signals[a] == sig) {
151 : /* If this is a real sigaction pointer... */
152 2 : if ((s_OldActions[a].sa_flags & SA_SIGINFO) != 0) {
153 : /*
154 : * On Mac OS X, sigaction() can return a "struct sigaction"
155 : * with SA_SIGINFO set but with a NULL sa_sigaction if no
156 : * signal handler was previously registered. This is allowed
157 : * by POSIX, which does not require a struct returned by
158 : * sigaction() to be intelligible. We check for NULL here to
159 : * avoid a crash.
160 : */
161 0 : if (s_OldActions[a].sa_sigaction != NULL) {
162 : /* then call the old handler. */
163 0 : s_OldActions[a].sa_sigaction(sig, info, uc);
164 0 : NaClSignalHandleCustomCrashHandler(sig);
165 0 : break;
166 : }
167 : } else {
168 : /* otherwise check if it is a real signal pointer */
169 2 : if ((s_OldActions[a].sa_handler != SIG_DFL) &&
170 0 : (s_OldActions[a].sa_handler != SIG_IGN)) {
171 : /* and call the old signal. */
172 0 : s_OldActions[a].sa_handler(sig);
173 0 : NaClSignalHandleCustomCrashHandler(sig);
174 0 : break;
175 : }
176 : }
177 : /*
178 : * We matched the signal, but didn't handle it, so we emulate
179 : * the default behavior which is to exit the app with the signal
180 : * number as the error code.
181 : */
182 2 : NaClExit(-sig);
183 : }
184 : }
185 0 : }
186 :
187 : /*
188 : * This function checks whether we can dispatch the signal to an
189 : * untrusted exception handler. If we can, it modifies the register
190 : * state to call the handler and writes a stack frame into into
191 : * untrusted address space, and returns true. Otherwise, it returns
192 : * false.
193 : */
194 115363 : static int DispatchToUntrustedHandler(struct NaClAppThread *natp,
195 : struct NaClSignalContext *regs) {
196 115363 : struct NaClApp *nap = natp->nap;
197 : uintptr_t frame_addr;
198 : volatile struct NaClExceptionFrame *frame;
199 : uint32_t new_stack_ptr;
200 : uintptr_t context_user_addr;
201 :
202 115363 : if (!NaClSignalCheckSandboxInvariants(regs, natp)) {
203 0 : return 0;
204 : }
205 115363 : if (nap->exception_handler == 0) {
206 12 : return 0;
207 : }
208 115351 : if (natp->exception_flag) {
209 1 : return 0;
210 : }
211 :
212 115350 : natp->exception_flag = 1;
213 :
214 115350 : if (natp->exception_stack == 0) {
215 115309 : new_stack_ptr = regs->stack_ptr - NACL_STACK_RED_ZONE;
216 : } else {
217 41 : new_stack_ptr = natp->exception_stack;
218 : }
219 : /* Allocate space for the stack frame, and ensure its alignment. */
220 115350 : new_stack_ptr -=
221 : sizeof(struct NaClExceptionFrame) - NACL_STACK_PAD_BELOW_ALIGN;
222 115350 : new_stack_ptr = new_stack_ptr & ~NACL_STACK_ALIGN_MASK;
223 115350 : new_stack_ptr -= NACL_STACK_ARGS_SIZE;
224 115350 : new_stack_ptr -= NACL_STACK_PAD_BELOW_ALIGN;
225 115350 : frame_addr = NaClUserToSysAddrRange(nap, new_stack_ptr,
226 : sizeof(struct NaClExceptionFrame));
227 115350 : if (frame_addr == kNaClBadAddress) {
228 : /* We cannot write the stack frame. */
229 1 : return 0;
230 : }
231 115349 : context_user_addr = new_stack_ptr + offsetof(struct NaClExceptionFrame,
232 : context);
233 :
234 115349 : frame = (struct NaClExceptionFrame *) frame_addr;
235 115349 : NaClSignalSetUpExceptionFrame(frame, regs, context_user_addr);
236 :
237 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
238 115349 : regs->prog_ctr = nap->exception_handler;
239 115349 : regs->stack_ptr = new_stack_ptr;
240 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
241 : regs->rdi = context_user_addr; /* Argument 1 */
242 : regs->prog_ctr = NaClUserToSys(nap, nap->exception_handler);
243 : regs->stack_ptr = NaClUserToSys(nap, new_stack_ptr);
244 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
245 : /*
246 : * Returning from the exception handler is not possible, so to avoid
247 : * any confusion that might arise from jumping to an uninitialised
248 : * address, we set the return address to zero.
249 : */
250 : regs->lr = 0;
251 : regs->r0 = context_user_addr; /* Argument 1 */
252 : regs->prog_ctr = NaClUserToSys(nap, nap->exception_handler);
253 : regs->stack_ptr = NaClUserToSys(nap, new_stack_ptr);
254 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
255 : regs->return_addr = 0;
256 : regs->a0 = context_user_addr;
257 : regs->prog_ctr = NaClUserToSys(nap, nap->exception_handler);
258 : regs->stack_ptr = NaClUserToSys(nap, new_stack_ptr);
259 : /*
260 : * Per Linux/MIPS convention, PIC functions assume that t9 holds
261 : * the function's address on entry.
262 : */
263 : regs->t9 = regs->prog_ctr;
264 : #else
265 : # error Unsupported architecture
266 : #endif
267 :
268 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
269 115349 : regs->flags &= ~NACL_X86_DIRECTION_FLAG;
270 : #endif
271 :
272 115349 : return 1;
273 : }
274 :
275 140375 : static void SignalCatch(int sig, siginfo_t *info, void *uc) {
276 : struct NaClSignalContext sig_ctx;
277 : int is_untrusted;
278 : struct NaClAppThread *natp;
279 :
280 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
281 : /*
282 : * Reset the x86 direction flag. New versions of gcc and libc
283 : * assume that the direction flag is clear on entry to a function,
284 : * as the x86 ABI requires. However, untrusted code can set this
285 : * flag, and versions of Linux before 2.6.25 do not clear the flag
286 : * before running the signal handler, so we clear it here for safety.
287 : * See http://code.google.com/p/nativeclient/issues/detail?id=1495
288 : */
289 140375 : __asm__("cld");
290 : #endif
291 :
292 140375 : NaClSignalContextFromHandler(&sig_ctx, uc);
293 140375 : GetCurrentThread(&sig_ctx, &is_untrusted, &natp);
294 :
295 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
296 : /*
297 : * On Linux, the kernel does not restore %gs when entering the
298 : * signal handler, so we must do that here. We need to do this for
299 : * TLS to work and for glibc's syscall wrappers to work, because
300 : * some builds of glibc fetch a syscall function pointer from the
301 : * static TLS area. There is the potential for vulnerabilities if
302 : * we call glibc without restoring %gs (such as
303 : * http://code.google.com/p/nativeclient/issues/detail?id=1607),
304 : * although the risk is reduced because the untrusted %gs segment
305 : * has an extent of only 4 bytes (see
306 : * http://code.google.com/p/nativeclient/issues/detail?id=2176).
307 : *
308 : * Note that, in comparison, Breakpad tries to avoid using libc
309 : * calls at all when a crash occurs.
310 : *
311 : * For comparison, on Mac OS X, the kernel *does* restore the
312 : * original %gs when entering the signal handler. On Mac, our
313 : * assignment to %gs here wouldn't be necessary, but it wouldn't be
314 : * harmful either. However, this code is not currently used on Mac
315 : * OS X.
316 : *
317 : * Both Linux and Mac OS X necessarily restore %cs, %ds, and %ss
318 : * otherwise we would have a hard time handling signals generated by
319 : * untrusted code at all.
320 : *
321 : * Note that we check natp (which is based on %gs) rather than
322 : * is_untrusted (which is based on %cs) because we need to handle
323 : * the case where %gs is set to the untrusted-code value but %cs is
324 : * not.
325 : *
326 : * GCC's stack protector (-fstack-protector) will make use of %gs even before
327 : * we have a chance to restore it. It is important that this function is not
328 : * compiled with -fstack-protector.
329 : */
330 140375 : if (natp != NULL) {
331 121191 : NaClSetGs(natp->user.trusted_gs);
332 : }
333 : #endif
334 :
335 140375 : if (sig != SIGINT && sig != SIGQUIT) {
336 140375 : if (NaClThreadSuspensionSignalHandler(sig, &sig_ctx, is_untrusted, natp)) {
337 10594 : NaClSignalContextToHandler(uc, &sig_ctx);
338 : /* Resume untrusted code using possibly modified register state. */
339 10594 : return;
340 : }
341 : }
342 :
343 129764 : if (is_untrusted &&
344 3057 : (sig == SIGSEGV || sig == SIGILL || sig == SIGFPE ||
345 : (NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips && sig == SIGTRAP))) {
346 115363 : if (DispatchToUntrustedHandler(natp, &sig_ctx)) {
347 115349 : NaClSignalContextToHandler(uc, &sig_ctx);
348 : /* Resume untrusted code using the modified register state. */
349 115349 : return;
350 : }
351 : }
352 :
353 14415 : if (g_handler_func != NULL) {
354 14399 : g_handler_func(sig, &sig_ctx, is_untrusted);
355 14399 : return;
356 : }
357 :
358 16 : NaClSignalHandleUntrusted(sig, &sig_ctx, is_untrusted);
359 :
360 2 : FindAndRunHandler(sig, info, uc);
361 : }
362 :
363 :
364 : /*
365 : * Check that the current process has no signal handlers registered
366 : * that we won't override with safe handlers.
367 : *
368 : * We want to discourage Chrome or libraries from registering signal
369 : * handlers themselves, because those signal handlers are often not
370 : * safe when triggered from untrusted code. For background, see:
371 : * http://code.google.com/p/nativeclient/issues/detail?id=1607
372 : */
373 289 : static void AssertNoOtherSignalHandlers(void) {
374 : unsigned int index;
375 : int signum;
376 : char handled_by_nacl[NSIG];
377 :
378 : /* 0 is not a valid signal number. */
379 18785 : for (signum = 1; signum < NSIG; signum++) {
380 18496 : handled_by_nacl[signum] = 0;
381 : }
382 3468 : for (index = 0; index < NACL_ARRAY_SIZE(s_Signals); index++) {
383 3179 : signum = s_Signals[index];
384 3179 : CHECK(signum > 0);
385 3179 : CHECK(signum < NSIG);
386 3179 : handled_by_nacl[signum] = 1;
387 : }
388 18785 : for (signum = 1; signum < NSIG; signum++) {
389 : struct sigaction sa;
390 :
391 18496 : if (handled_by_nacl[signum])
392 3179 : continue;
393 :
394 15317 : if (sigaction(signum, NULL, &sa) != 0) {
395 : /*
396 : * Don't complain if the kernel does not consider signum to be a
397 : * valid signal number, which produces EINVAL.
398 : */
399 578 : if (errno != EINVAL) {
400 0 : NaClLog(LOG_FATAL, "AssertNoOtherSignalHandlers: "
401 : "sigaction() call failed for signal %d: errno=%d\n",
402 0 : signum, errno);
403 : }
404 : } else {
405 14739 : if ((sa.sa_flags & SA_SIGINFO) == 0) {
406 14739 : if (sa.sa_handler == SIG_DFL || sa.sa_handler == SIG_IGN)
407 14739 : continue;
408 : } else {
409 : /*
410 : * It is not strictly legal for sa_sigaction to contain NULL
411 : * or SIG_IGN, but Valgrind reports SIG_IGN for signal 64, so
412 : * we allow it here.
413 : */
414 0 : if (sa.sa_sigaction == NULL ||
415 0 : sa.sa_sigaction == (void (*)(int, siginfo_t *, void *)) SIG_IGN)
416 0 : continue;
417 : }
418 0 : NaClLog(LOG_FATAL, "AssertNoOtherSignalHandlers: "
419 : "A signal handler is registered for signal %d\n", signum);
420 : }
421 : }
422 289 : }
423 :
424 289 : void NaClSignalHandlerInit(void) {
425 : struct sigaction sa;
426 : unsigned int a;
427 :
428 : /*
429 : * Android adds a handler for SIGPIPE in the dynamic linker.
430 : */
431 : if (NACL_ANDROID)
432 : CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
433 :
434 289 : AssertNoOtherSignalHandlers();
435 :
436 289 : memset(&sa, 0, sizeof(sa));
437 289 : sigemptyset(&sa.sa_mask);
438 289 : sa.sa_sigaction = SignalCatch;
439 289 : sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
440 :
441 : /*
442 : * Mask all signals we catch to prevent re-entry.
443 : *
444 : * In particular, NACL_THREAD_SUSPEND_SIGNAL must be masked while we
445 : * are handling a fault from untrusted code, otherwise the
446 : * suspension signal will interrupt the trusted fault handler. That
447 : * would cause NaClAppThreadGetSuspendedRegisters() to report
448 : * trusted-code register state rather than untrusted-code register
449 : * state from the point where the fault occurred.
450 : */
451 3468 : for (a = 0; a < NACL_ARRAY_SIZE(s_Signals); a++) {
452 3179 : sigaddset(&sa.sa_mask, s_Signals[a]);
453 : }
454 :
455 : /* Install all handlers */
456 3468 : for (a = 0; a < NACL_ARRAY_SIZE(s_Signals); a++) {
457 3179 : if (sigaction(s_Signals[a], &sa, &s_OldActions[a]) != 0) {
458 0 : NaClLog(LOG_FATAL, "Failed to install handler for %d.\n\tERR:%s\n",
459 0 : s_Signals[a], strerror(errno));
460 : }
461 : }
462 289 : }
463 :
464 11 : void NaClSignalHandlerFini(void) {
465 : unsigned int a;
466 :
467 : /* Remove all handlers */
468 132 : for (a = 0; a < NACL_ARRAY_SIZE(s_Signals); a++) {
469 121 : if (sigaction(s_Signals[a], &s_OldActions[a], NULL) != 0) {
470 0 : NaClLog(LOG_FATAL, "Failed to unregister handler for %d.\n\tERR:%s\n",
471 0 : s_Signals[a], strerror(errno));
472 : }
473 : }
474 11 : }
|