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 : /*
8 : * POSIX-specific routines for verifying that Data Execution Prevention is
9 : * functional.
10 : */
11 :
12 : #include <setjmp.h>
13 : #include <stdlib.h>
14 : #include <signal.h>
15 :
16 : #include "native_client/src/include/nacl_compiler_annotations.h"
17 : #include "native_client/src/shared/platform/nacl_check.h"
18 : #include "native_client/src/trusted/platform_qualify/nacl_dep_qualify.h"
19 :
20 : #if NACL_OSX
21 : #include <mach/mach.h>
22 : #endif
23 :
24 : #if (NACL_OSX && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \
25 : NACL_BUILD_SUBARCH == 64)
26 : # define EXPECTED_SIGNAL SIGBUS
27 : #else
28 : # define EXPECTED_SIGNAL SIGSEGV
29 : #endif
30 :
31 : static struct sigaction previous_sigaction;
32 : static struct sigaction try_sigaction;
33 : static sigjmp_buf try_state;
34 :
35 0 : static void signal_catch(int sig) {
36 0 : siglongjmp(try_state, sig);
37 0 : }
38 :
39 : static void setup_signals(void) {
40 267 : try_sigaction.sa_handler = signal_catch;
41 267 : sigemptyset(&try_sigaction.sa_mask);
42 267 : try_sigaction.sa_flags = SA_RESETHAND;
43 :
44 267 : (void) sigaction(EXPECTED_SIGNAL, &try_sigaction, &previous_sigaction);
45 267 : }
46 :
47 : static void restore_signals(void) {
48 267 : (void) sigaction(EXPECTED_SIGNAL, &previous_sigaction, 0);
49 267 : }
50 :
51 : #if NACL_OSX
52 :
53 : /*
54 : * If present, Breakpad's handler will swallow the hardware exception that
55 : * the test triggers before its signal handler can respond to it. Temporarily
56 : * disable Breakpad's handler to allow the system's in-kernel handler to
57 : * transform the exception into the signal that's expected here.
58 : */
59 :
60 : /*
61 : * <mach/mach_types.defs> says that these arrays have room for 32 elements,
62 : * not EXC_TYPES_COUNT. task_swap_exception_ports expects there to be room for
63 : * 32.
64 : */
65 : #define MAX_EXCEPTION_PORTS 32
66 :
67 : typedef struct {
68 : exception_mask_t masks[MAX_EXCEPTION_PORTS];
69 : exception_handler_t ports[MAX_EXCEPTION_PORTS];
70 : exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
71 : thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
72 : mach_msg_type_number_t count;
73 : } MachExceptionHandlerData;
74 :
75 : static void DisableMachExceptionHandler(
76 267 : MachExceptionHandlerData *saved_handlers) {
77 267 : kern_return_t kr = task_swap_exception_ports(
78 : mach_task_self(),
79 : EXC_MASK_BAD_ACCESS,
80 : MACH_PORT_NULL,
81 : EXCEPTION_DEFAULT,
82 : THREAD_STATE_NONE,
83 : (exception_mask_array_t) &saved_handlers->masks,
84 : &saved_handlers->count,
85 : (exception_handler_array_t) &saved_handlers->ports,
86 : (exception_behavior_array_t) &saved_handlers->behaviors,
87 : (exception_flavor_array_t) &saved_handlers->flavors);
88 801 : CHECK(kr == KERN_SUCCESS);
89 267 : }
90 :
91 : static void EnableMachExceptionHandler(
92 267 : MachExceptionHandlerData *saved_handlers) {
93 1068 : for (size_t index = 0; index < saved_handlers->count; ++index) {
94 267 : if (saved_handlers->ports[index] != MACH_PORT_NULL) {
95 28 : kern_return_t kr = task_set_exception_ports(
96 : mach_task_self(),
97 : saved_handlers->masks[index],
98 : saved_handlers->ports[index],
99 : saved_handlers->behaviors[index],
100 : saved_handlers->flavors[index]);
101 84 : CHECK(kr == KERN_SUCCESS);
102 28 : }
103 267 : }
104 267 : }
105 :
106 : #else
107 :
108 : typedef int MachExceptionHandlerData;
109 :
110 : static void DisableMachExceptionHandler(
111 : MachExceptionHandlerData *saved_handlers) {
112 : UNREFERENCED_PARAMETER(saved_handlers);
113 : }
114 :
115 : static void EnableMachExceptionHandler(
116 : MachExceptionHandlerData *saved_handlers) {
117 : UNREFERENCED_PARAMETER(saved_handlers);
118 : }
119 :
120 : #endif
121 :
122 533 : int NaClAttemptToExecuteDataAtAddr(char *thunk_buffer, size_t size) {
123 533 : int result;
124 533 : MachExceptionHandlerData saved_handlers;
125 533 : nacl_void_thunk thunk = NaClGenerateThunk(thunk_buffer, size);
126 :
127 533 : setup_signals();
128 533 : DisableMachExceptionHandler(&saved_handlers);
129 :
130 533 : if (0 == sigsetjmp(try_state, 1)) {
131 267 : thunk();
132 267 : result = 0;
133 267 : } else {
134 266 : result = 1;
135 : }
136 :
137 267 : EnableMachExceptionHandler(&saved_handlers);
138 267 : restore_signals();
139 :
140 267 : return result;
141 : }
142 :
143 : /*
144 : * Returns 1 if Data Execution Prevention is present and working.
145 : */
146 : int NaClAttemptToExecuteData(void) {
147 265 : int result;
148 530 : char *thunk_buffer = malloc(64);
149 265 : if (NULL == thunk_buffer) {
150 0 : return 0;
151 : }
152 265 : result = NaClAttemptToExecuteDataAtAddr(thunk_buffer, 64);
153 265 : free(thunk_buffer);
154 265 : return result;
155 265 : }
|