1 : /*
2 : * Copyright (c) 2013 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 :
12 : #include "native_client/src/shared/platform/nacl_check.h"
13 : #include "native_client/src/shared/platform/nacl_log.h"
14 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
15 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
16 :
17 :
18 : /*
19 : * NaCl uses POSIX signal handling on Linux, but not on Mac OS X. We
20 : * register a signal stack on Mac OS X anyway, though, for safety, to
21 : * prevent a signal handler from running on an untrusted stack just in
22 : * case a signal handler gets left registered.
23 : */
24 :
25 : /* Use 4K more than the minimum to allow breakpad to run. */
26 : static uint32_t g_signal_stack_size = SIGSTKSZ + 4096;
27 :
28 : #define STACK_GUARD_SIZE NACL_PAGESIZE
29 :
30 0 : void NaClSignalStackSetSize(uint32_t size) {
31 0 : g_signal_stack_size = size;
32 0 : }
33 :
34 20878 : int NaClSignalStackAllocate(void **result) {
35 : /*
36 : * We use mmap() to allocate the signal stack for two reasons:
37 : *
38 : * 1) By page-aligning the memory allocation (which malloc() does
39 : * not do for small allocations), we avoid allocating any real
40 : * memory in the common case in which the signal handler is never
41 : * run.
42 : *
43 : * 2) We get to create a guard page, to guard against the unlikely
44 : * occurrence of the signal handler both overrunning and doing so in
45 : * an exploitable way.
46 : */
47 20878 : uint8_t *stack = mmap(NULL, g_signal_stack_size + STACK_GUARD_SIZE,
48 : PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
49 : -1, 0);
50 20878 : if (stack == MAP_FAILED) {
51 0 : return 0;
52 : }
53 : /* We assume that the stack grows downwards. */
54 20878 : if (mprotect(stack, STACK_GUARD_SIZE, PROT_NONE) != 0) {
55 0 : NaClLog(LOG_FATAL, "Failed to mprotect() the stack guard page:\n\t%s\n",
56 0 : strerror(errno));
57 0 : }
58 20878 : *result = stack;
59 20878 : return 1;
60 20878 : }
61 :
62 20694 : void NaClSignalStackFree(void *stack) {
63 62082 : CHECK(stack != NULL);
64 20694 : if (munmap(stack, g_signal_stack_size + STACK_GUARD_SIZE) != 0) {
65 0 : NaClLog(LOG_FATAL, "Failed to munmap() signal stack:\n\t%s\n",
66 0 : strerror(errno));
67 0 : }
68 20694 : }
69 :
70 20878 : void NaClSignalStackRegister(void *stack) {
71 : /*
72 : * If we set up signal handlers, we must ensure that any thread that
73 : * runs untrusted code has an alternate signal stack set up. The
74 : * default for a new thread is to use the stack pointer from the
75 : * point at which the fault occurs, but it would not be safe to use
76 : * untrusted code's %esp/%rsp value.
77 : */
78 20878 : stack_t st;
79 20878 : st.ss_size = g_signal_stack_size;
80 20878 : st.ss_sp = ((uint8_t *) stack) + STACK_GUARD_SIZE;
81 20878 : st.ss_flags = 0;
82 20878 : if (sigaltstack(&st, NULL) != 0) {
83 0 : NaClLog(LOG_FATAL, "Failed to register signal stack:\n\t%s\n",
84 0 : strerror(errno));
85 0 : }
86 20878 : }
87 :
88 : void NaClSignalStackUnregister(void) {
89 : /*
90 : * Unregister the signal stack in case a fault occurs between the
91 : * thread deallocating the signal stack and exiting. Such a fault
92 : * could be unsafe if the address space were reallocated before the
93 : * fault, although that is unlikely.
94 : */
95 20694 : stack_t st;
96 : #if NACL_OSX
97 : /*
98 : * This is a workaround for a bug in Mac OS X's libc, in which new
99 : * versions of the sigaltstack() wrapper return ENOMEM if ss_size is
100 : * less than MINSIGSTKSZ, even when ss_size should be ignored
101 : * because we are unregistering the signal stack.
102 : * See http://code.google.com/p/nativeclient/issues/detail?id=1053
103 : */
104 20694 : st.ss_size = MINSIGSTKSZ;
105 : #else
106 : st.ss_size = 0;
107 : #endif
108 20694 : st.ss_sp = NULL;
109 20694 : st.ss_flags = SS_DISABLE;
110 20694 : if (sigaltstack(&st, NULL) != 0) {
111 0 : NaClLog(LOG_FATAL, "Failed to unregister signal stack:\n\t%s\n",
112 0 : strerror(errno));
113 0 : }
114 20694 : }
|