Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: src/trusted/service_runtime/osx/mach_exception_handler.c

Issue 12207165: Mac x86_64: Mach exception support (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client/
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. 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 3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file. 4 * found in the LICENSE file.
5 */ 5 */
6 6
7 #include "native_client/src/trusted/service_runtime/osx/mach_exception_handler.h " 7 #include "native_client/src/trusted/service_runtime/osx/mach_exception_handler.h "
8 8
9 #include <mach/mach.h> 9 #include <mach/mach.h>
10 #include <mach/mach_vm.h> 10 #include <mach/mach_vm.h>
11 #include <mach/thread_status.h> 11 #include <mach/thread_status.h>
12 #include <pthread.h> 12 #include <pthread.h>
13 #include <stddef.h> 13 #include <stddef.h>
14 #include <stdio.h> 14 #include <stdio.h>
15 #include <stdlib.h> 15 #include <stdlib.h>
16 16
17 #include "native_client/src/include/nacl_macros.h" 17 #include "native_client/src/include/nacl_macros.h"
18 #include "native_client/src/include/portability.h" 18 #include "native_client/src/include/portability.h"
19 #include "native_client/src/shared/platform/nacl_check.h" 19 #include "native_client/src/shared/platform/nacl_check.h"
20 #include "native_client/src/shared/platform/nacl_log.h" 20 #include "native_client/src/shared/platform/nacl_log.h"
21 #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h" 21 #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
22 #include "native_client/src/trusted/service_runtime/nacl_app.h" 22 #include "native_client/src/trusted/service_runtime/nacl_app.h"
23 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h" 23 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
24 #include "native_client/src/trusted/service_runtime/nacl_config.h" 24 #include "native_client/src/trusted/service_runtime/nacl_config.h"
25 #include "native_client/src/trusted/service_runtime/nacl_exc.h" 25 #include "native_client/src/trusted/service_runtime/nacl_exc.h"
26 #include "native_client/src/trusted/service_runtime/nacl_exception.h" 26 #include "native_client/src/trusted/service_runtime/nacl_exception.h"
27 #include "native_client/src/trusted/service_runtime/nacl_globals.h" 27 #include "native_client/src/trusted/service_runtime/nacl_globals.h"
28 #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h" 28 #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h"
29 #include "native_client/src/trusted/service_runtime/osx/crash_filter.h"
30 #include "native_client/src/trusted/service_runtime/osx/mach_thread_map.h"
29 #include "native_client/src/trusted/service_runtime/sel_ldr.h" 31 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
30 #include "native_client/src/trusted/service_runtime/sel_rt.h" 32 #include "native_client/src/trusted/service_runtime/sel_rt.h"
31 33
32 /* Only handle x86_32 for now. */ 34 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
33 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
34 35
35 36
36 /* 37 /*
37 * MIG generated message pump from /usr/include/mach/exc.defs 38 * MIG generated message pump from /usr/include/mach/exc.defs
38 * Tweaked to place in an isolated namespace. 39 * Tweaked to place in an isolated namespace.
39 */ 40 */
40 boolean_t nacl_exc_server( 41 boolean_t nacl_exc_server(
41 mach_msg_header_t *InHeadP, 42 mach_msg_header_t *InHeadP,
42 mach_msg_header_t *OutHeadP); 43 mach_msg_header_t *OutHeadP);
43 44
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 if (write(pipe_fd, &buf, sizeof(buf)) != sizeof(buf)) { 86 if (write(pipe_fd, &buf, sizeof(buf)) != sizeof(buf)) {
86 NaClLog(LOG_FATAL, "FireDebugStubEvent: Can't send debug stub event\n"); 87 NaClLog(LOG_FATAL, "FireDebugStubEvent: Can't send debug stub event\n");
87 } 88 }
88 } 89 }
89 90
90 static int HandleException(mach_port_t thread_port, 91 static int HandleException(mach_port_t thread_port,
91 exception_type_t exception, int *is_untrusted) { 92 exception_type_t exception, int *is_untrusted) {
92 mach_msg_type_number_t size; 93 mach_msg_type_number_t size;
93 x86_thread_state_t regs; 94 x86_thread_state_t regs;
94 kern_return_t result; 95 kern_return_t result;
96 #if NACL_BUILD_SUBARCH == 32
95 uint16_t trusted_cs = NaClGetGlobalCs(); 97 uint16_t trusted_cs = NaClGetGlobalCs();
96 uint16_t trusted_ds = NaClGetGlobalDs(); 98 uint16_t trusted_ds = NaClGetGlobalDs();
99 #endif
97 uint32_t nacl_thread_index; 100 uint32_t nacl_thread_index;
98 struct NaClApp *nap; 101 struct NaClApp *nap;
99 struct NaClAppThread *natp; 102 struct NaClAppThread *natp;
100 struct NaClExceptionFrame frame; 103 struct NaClExceptionFrame frame;
101 uintptr_t frame_addr_user; 104 uintptr_t frame_addr_user;
102 uintptr_t frame_addr_sys; 105 uintptr_t frame_addr_sys;
103 106
104 /* Assume untrusted crash until we know otherwise. */ 107 /* Assume untrusted crash until we know otherwise. */
105 *is_untrusted = TRUE; 108 *is_untrusted = TRUE;
106 109
107 /* Capture the register state of the 'excepting' thread. */ 110 /* Capture the register state of the 'excepting' thread. */
108 size = sizeof(regs) / sizeof(natural_t); 111 size = x86_THREAD_STATE_COUNT;
109 result = thread_get_state(thread_port, x86_THREAD_STATE, 112 result = thread_get_state(thread_port, x86_THREAD_STATE,
110 (void *) &regs, &size); 113 (thread_state_t) &regs, &size);
111 if (result != KERN_SUCCESS) { 114 if (result != KERN_SUCCESS) {
112 return 0; 115 return 0;
113 } 116 }
117 #if NACL_BUILD_SUBARCH == 32
118 CHECK(regs.tsh.flavor == x86_THREAD_STATE32);
119 #elif NACL_BUILD_SUBARCH == 64
120 CHECK(regs.tsh.flavor == x86_THREAD_STATE64);
121 #endif
114 122
123 #if NACL_BUILD_SUBARCH == 32
115 /* 124 /*
116 * If trusted_cs is 0 (which is not a usable segment selector), the 125 * If trusted_cs is 0 (which is not a usable segment selector), the
117 * sandbox has not been initialised yet, so there can be no untrusted 126 * sandbox has not been initialised yet, so there can be no untrusted
118 * code running. 127 * code running.
119 */ 128 */
120 if (trusted_cs == 0) { 129 if (trusted_cs == 0) {
121 *is_untrusted = FALSE; 130 *is_untrusted = FALSE;
122 return 0; 131 return 0;
123 } 132 }
133 #endif
124 134
125 /* 135 /*
126 * If the current code segment is the trusted one, we aren't in the 136 * If the current code segment is the trusted one, we aren't in the
127 * sandbox. 137 * sandbox.
128 * TODO(bradnelson): This makes the potentially false assumption that cs is 138 * TODO(bradnelson): This makes the potentially false assumption that cs is
129 * the last thing to change when switching into untrusted code. We need 139 * the last thing to change when switching into untrusted code. We need
130 * tests to vet this. 140 * tests to vet this.
131 */ 141 */
142 #if NACL_BUILD_SUBARCH == 32
132 if (regs.uts.ts32.__cs == trusted_cs) { 143 if (regs.uts.ts32.__cs == trusted_cs) {
133 /* 144 /*
134 * If we are single-stepping, allow NaClSwitchRemainingRegsViaECX() 145 * If we are single-stepping, allow NaClSwitchRemainingRegsViaECX()
135 * to continue in order to restore control to untrusted code. 146 * to continue in order to restore control to untrusted code.
136 */ 147 */
137 if (exception == EXC_BREAKPOINT && 148 if (exception == EXC_BREAKPOINT &&
138 (regs.uts.ts32.__eflags & NACL_X86_TRAP_FLAG) != 0 && 149 (regs.uts.ts32.__eflags & NACL_X86_TRAP_FLAG) != 0 &&
139 regs.uts.ts32.__eip >= (uintptr_t) NaClSwitchRemainingRegsViaECX && 150 regs.uts.ts32.__eip >= (uintptr_t) NaClSwitchRemainingRegsViaECX &&
140 regs.uts.ts32.__eip < (uintptr_t) NaClSwitchRemainingRegsAsmEnd) { 151 regs.uts.ts32.__eip < (uintptr_t) NaClSwitchRemainingRegsAsmEnd) {
141 return 1; 152 return 1;
142 } 153 }
143 *is_untrusted = FALSE; 154 *is_untrusted = FALSE;
144 return 0; 155 return 0;
145 } 156 }
146 157
147 /* 158 /*
148 * We can get the thread index from the segment selector used for TLS 159 * We can get the thread index from the segment selector used for TLS
149 * from %gs >> 3. 160 * from %gs >> 3.
150 * TODO(bradnelson): Migrate that knowledge to a single shared location. 161 * TODO(bradnelson): Migrate that knowledge to a single shared location.
151 */ 162 */
152 nacl_thread_index = regs.uts.ts32.__gs >> 3; 163 nacl_thread_index = regs.uts.ts32.__gs >> 3;
164 #elif NACL_BUILD_SUBARCH == 64
165 nacl_thread_index = GetNaClThreadIndexForMachThread(thread_port);
166 if (!nacl_thread_index) {
Mark Seaborn 2013/02/14 00:37:54 Make this "if (nacl_thread_index == NACL_TLS_INDEX
167 *is_untrusted = FALSE;
168 return 0;
169 }
170 #endif
171
153 natp = NaClAppThreadGetFromIndex(nacl_thread_index); 172 natp = NaClAppThreadGetFromIndex(nacl_thread_index);
154 nap = natp->nap; 173 nap = natp->nap;
174 #if NACL_BUILD_SUBARCH == 64
175 *is_untrusted = NaClMachThreadStateIsInUntrusted(natp, &regs);
176 /*
177 * If trusted code accidentally jumped to untrusted code, don't let the
178 * untrusted exception handler take over.
179 */
180 if (*is_untrusted &&
181 (natp->suspend_state & NACL_APP_THREAD_UNTRUSTED) == 0) {
182 *is_untrusted = 0;
183 }
184 if (!*is_untrusted) {
185 return 0;
186 }
187 #endif
155 188
156 if (nap->enable_faulted_thread_queue) { 189 if (nap->enable_faulted_thread_queue) {
157 /* 190 /*
158 * If we are single-stepping, step through until we reach untrusted code. 191 * If we are single-stepping, step through until we reach untrusted code.
159 */ 192 */
193 #if NACL_BUILD_SUBARCH == 32
160 if (exception == EXC_BREAKPOINT && 194 if (exception == EXC_BREAKPOINT &&
161 (regs.uts.ts32.__eflags & NACL_X86_TRAP_FLAG) != 0) { 195 (regs.uts.ts32.__eflags & NACL_X86_TRAP_FLAG) != 0) {
162 if (regs.uts.ts32.__eip >= nap->all_regs_springboard.start_addr && 196 if (regs.uts.ts32.__eip >= nap->all_regs_springboard.start_addr &&
163 regs.uts.ts32.__eip < nap->all_regs_springboard.end_addr) { 197 regs.uts.ts32.__eip < nap->all_regs_springboard.end_addr) {
164 return 1; 198 return 1;
165 } 199 }
166 /* 200 /*
167 * Step through the instruction we have been asked to restore 201 * Step through the instruction we have been asked to restore
168 * control to. 202 * control to.
169 */ 203 */
170 if (regs.uts.ts32.__eip == natp->user.gs_segment.new_prog_ctr) { 204 if (regs.uts.ts32.__eip == natp->user.gs_segment.new_prog_ctr) {
171 return 1; 205 return 1;
172 } 206 }
173 } 207 }
208 #endif
174 209
175 /* 210 /*
176 * Increment the kernel's thread suspension count so that the 211 * Increment the kernel's thread suspension count so that the
177 * thread remains suspended after we return. 212 * thread remains suspended after we return.
178 */ 213 */
179 result = thread_suspend(thread_port); 214 result = thread_suspend(thread_port);
180 if (result != KERN_SUCCESS) { 215 if (result != KERN_SUCCESS) {
181 NaClLog(LOG_FATAL, "HandleException: thread_suspend() call failed\n"); 216 NaClLog(LOG_FATAL, "HandleException: thread_suspend() call failed\n");
182 } 217 }
183 /* 218 /*
(...skipping 12 matching lines...) Expand all
196 * Ignore all but bad accesses for now. 231 * Ignore all but bad accesses for now.
197 * TODO(bradnelson): eventually consider these too: 232 * TODO(bradnelson): eventually consider these too:
198 * EXC_BAD_INSTRUCTION 233 * EXC_BAD_INSTRUCTION
199 * EXC_ARITHMETIC 234 * EXC_ARITHMETIC
200 * EXC_BREAKPOINT 235 * EXC_BREAKPOINT
201 */ 236 */
202 if (exception != EXC_BAD_ACCESS) { 237 if (exception != EXC_BAD_ACCESS) {
203 return 0; 238 return 0;
204 } 239 }
205 240
241 /* Don't handle if no exception handler is set. */
242 if (nap->exception_handler == 0) {
243 return 0;
244 }
245
206 /* Don't handle it if the exception flag is set. */ 246 /* Don't handle it if the exception flag is set. */
207 if (natp->exception_flag) { 247 if (natp->exception_flag) {
208 return 0; 248 return 0;
209 } 249 }
210 /* Set the flag. */ 250 /* Set the flag. */
211 natp->exception_flag = 1; 251 natp->exception_flag = 1;
212 252
213 /* Don't handle if no exception handler is set. */
214 if (nap->exception_handler == 0) {
215 return 0;
216 }
217
218 /* Get location of exception stack frame. */ 253 /* Get location of exception stack frame. */
219 if (natp->exception_stack) { 254 if (natp->exception_stack) {
220 frame_addr_user = natp->exception_stack; 255 frame_addr_user = natp->exception_stack;
221 } else { 256 } else {
222 /* If not set default to user stack. */ 257 /* If not set default to user stack. */
223 frame_addr_user = regs.uts.ts32.__esp; 258 #if NACL_BUILD_SUBARCH == 32
259 frame_addr_user = regs.uts.ts32.__esp - NACL_STACK_RED_ZONE;
260 #elif NACL_BUILD_SUBARCH == 64
261 frame_addr_user = (regs.uts.ts64.__rsp & 0xffffffff) - NACL_STACK_RED_ZONE;
Mark Seaborn 2013/02/14 00:37:54 Casting to uint32_t would be preferred over '& 0xf
262 #endif
224 } 263 }
225 264
226 /* Align stack frame properly. */ 265 /* Align stack frame properly. */
227 frame_addr_user -= 266 frame_addr_user -=
228 sizeof(struct NaClExceptionFrame) - NACL_STACK_PAD_BELOW_ALIGN; 267 sizeof(struct NaClExceptionFrame) - NACL_STACK_PAD_BELOW_ALIGN;
229 frame_addr_user &= ~NACL_STACK_ALIGN_MASK; 268 frame_addr_user &= ~NACL_STACK_ALIGN_MASK;
230 frame_addr_user -= NACL_STACK_PAD_BELOW_ALIGN; 269 frame_addr_user -= NACL_STACK_PAD_BELOW_ALIGN;
231 270
232 /* Convert from user to system space. */ 271 /* Convert from user to system space. */
233 frame_addr_sys = NaClUserToSysAddrRange( 272 frame_addr_sys = NaClUserToSysAddrRange(
234 nap, frame_addr_user, sizeof(struct NaClExceptionFrame)); 273 nap, frame_addr_user, sizeof(struct NaClExceptionFrame));
235 if (frame_addr_sys == kNaClBadAddress) { 274 if (frame_addr_sys == kNaClBadAddress) {
236 return 0; 275 return 0;
237 } 276 }
238 277
239 /* Set up the stack frame for the handler invocation. */ 278 /* Set up the stack frame for the handler invocation. */
240 frame.return_addr = 0; 279 frame.return_addr = 0;
280 #if NACL_BUILD_SUBARCH == 32
241 frame.context_ptr = frame_addr_user + 281 frame.context_ptr = frame_addr_user +
242 offsetof(struct NaClExceptionFrame, context); 282 offsetof(struct NaClExceptionFrame, context);
243 frame.context.prog_ctr = regs.uts.ts32.__eip; 283 frame.context.prog_ctr = regs.uts.ts32.__eip;
244 frame.context.stack_ptr = regs.uts.ts32.__esp; 284 frame.context.stack_ptr = regs.uts.ts32.__esp;
245 frame.context.frame_ptr = regs.uts.ts32.__ebp; 285 frame.context.frame_ptr = regs.uts.ts32.__ebp;
286 #elif NACL_BUILD_SUBARCH == 64
287 frame.context.prog_ctr = regs.uts.ts64.__rip;
288 frame.context.stack_ptr = regs.uts.ts64.__rsp;
289 frame.context.frame_ptr = regs.uts.ts64.__rbp;
290 #endif
246 291
247 /* 292 /*
248 * Write the stack frame into untrusted address space. We do not 293 * Write the stack frame into untrusted address space. We do not
249 * write to the memory directly because that will fault if the 294 * write to the memory directly because that will fault if the
250 * destination location is not writable. Faulting is OK for NaCl 295 * destination location is not writable. Faulting is OK for NaCl
251 * syscalls, but here we do not want to trigger an exception while 296 * syscalls, but here we do not want to trigger an exception while
252 * in the exception handler. The overhead of using a Mach system 297 * in the exception handler. The overhead of using a Mach system
253 * call to write to memory is acceptable here. 298 * call to write to memory is acceptable here.
254 */ 299 */
255 result = mach_vm_write(mach_task_self(), frame_addr_sys, 300 result = mach_vm_write(mach_task_self(), frame_addr_sys,
256 (uintptr_t) &frame, sizeof(frame)); 301 (uintptr_t) &frame, sizeof(frame));
257 if (result != KERN_SUCCESS) { 302 if (result != KERN_SUCCESS) {
258 return 0; 303 return 0;
259 } 304 }
260 305
261 /* Set up thread context to resume at handler. */ 306 /* Set up thread context to resume at handler. */
307 #if NACL_BUILD_SUBARCH == 32
262 natp->user.new_prog_ctr = nap->exception_handler; 308 natp->user.new_prog_ctr = nap->exception_handler;
263 natp->user.stack_ptr = frame_addr_user; 309 natp->user.stack_ptr = frame_addr_user;
310 #endif
264 /* TODO(bradnelson): put all registers in some default state. */ 311 /* TODO(bradnelson): put all registers in some default state. */
265 312
266 /* 313 /*
267 * Put registers in right place to land at NaClSwitchNoSSEViaECX 314 * Put registers in right place to land at NaClSwitchNoSSEViaECX
Mark Seaborn 2013/02/14 00:37:54 This comment should be inside "#if NACL_BUILD_SUBA
268 * This is required because: 315 * This is required because:
269 * - For an unknown reason thread_set_state resets %cs to the default 316 * - For an unknown reason thread_set_state resets %cs to the default
270 * value, even when set to something else, in current XNU versions. 317 * value, even when set to something else, in current XNU versions.
271 * - An examination of the XNU sources indicates 318 * - An examination of the XNU sources indicates
272 * that setting the code which state the thread state resets 319 * that setting the code which state the thread state resets
273 * %cs, %ds, %es, %ss to their default values in some early versions. 320 * %cs, %ds, %es, %ss to their default values in some early versions.
274 * (For instance: xnu-792.6.22/osfmk/i386/pcb.c:616) 321 * (For instance: xnu-792.6.22/osfmk/i386/pcb.c:616)
275 * This precludes going directly to the untrusted handler. 322 * This precludes going directly to the untrusted handler.
276 * Instead we call a variant of NaClSwitchNoSSE which takes a pointer 323 * Instead we call a variant of NaClSwitchNoSSE which takes a pointer
277 * to the thread user context in %ecx. 324 * to the thread user context in %ecx.
278 */ 325 */
326 #if NACL_BUILD_SUBARCH == 32
279 regs.uts.ts32.__eip = (uint32_t) &NaClSwitchNoSSEViaECX; 327 regs.uts.ts32.__eip = (uint32_t) &NaClSwitchNoSSEViaECX;
280 regs.uts.ts32.__cs = trusted_cs; 328 regs.uts.ts32.__cs = trusted_cs;
281 regs.uts.ts32.__ecx = (uint32_t) &natp->user; 329 regs.uts.ts32.__ecx = (uint32_t) &natp->user;
282 regs.uts.ts32.__ds = trusted_ds; 330 regs.uts.ts32.__ds = trusted_ds;
283 regs.uts.ts32.__es = trusted_ds; /* just for good measure */ 331 regs.uts.ts32.__es = trusted_ds; /* just for good measure */
284 regs.uts.ts32.__ss = trusted_ds; /* just for good measure */ 332 regs.uts.ts32.__ss = trusted_ds; /* just for good measure */
285 regs.uts.ts32.__eflags &= ~NACL_X86_DIRECTION_FLAG; 333 regs.uts.ts32.__eflags &= ~NACL_X86_DIRECTION_FLAG;
334 #elif NACL_BUILD_SUBARCH == 64
335 regs.uts.ts64.__rip = NaClUserToSys(nap, nap->exception_handler);
336 regs.uts.ts64.__rsp = frame_addr_sys;
337 regs.uts.ts64.__rflags &= ~NACL_X86_DIRECTION_FLAG;
338 regs.uts.ts64.__rbp = nap->mem_start;
339
340 /* Argument 1 */
341 regs.uts.ts64.__rdi = frame_addr_user +
342 offsetof(struct NaClExceptionFrame, context);
343 #endif
286 result = thread_set_state(thread_port, x86_THREAD_STATE, 344 result = thread_set_state(thread_port, x86_THREAD_STATE,
287 (void *) &regs, size); 345 (void *) &regs, size);
288 if (result != KERN_SUCCESS) { 346 if (result != KERN_SUCCESS) {
289 return 0; 347 return 0;
290 } 348 }
291 349
292 /* Return success, and resume the thread. */ 350 /* Return success, and resume the thread. */
293 return 1; 351 return 1;
294 } 352 }
295 353
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 failure: 621 failure:
564 if (data) { 622 if (data) {
565 if (MACH_PORT_NULL != data->exception_port) { 623 if (MACH_PORT_NULL != data->exception_port) {
566 mach_port_deallocate(current_task, data->exception_port); 624 mach_port_deallocate(current_task, data->exception_port);
567 } 625 }
568 free(data); 626 free(data);
569 } 627 }
570 return FALSE; 628 return FALSE;
571 } 629 }
572 630
573 #else /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 */ 631 #endif /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 */
574
575 int NaClInterceptMachExceptions(void) {
576 return FALSE;
577 }
578
579 #endif /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 */
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698