Chromium Code Reviews| Index: src/trusted/service_runtime/osx/mach_exception_handler.c |
| =================================================================== |
| --- src/trusted/service_runtime/osx/mach_exception_handler.c (revision 10790) |
| +++ src/trusted/service_runtime/osx/mach_exception_handler.c (working copy) |
| @@ -26,11 +26,13 @@ |
| #include "native_client/src/trusted/service_runtime/nacl_exception.h" |
| #include "native_client/src/trusted/service_runtime/nacl_globals.h" |
| #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h" |
| +#include "native_client/src/trusted/service_runtime/nacl_tls.h" |
| +#include "native_client/src/trusted/service_runtime/osx/mach_thread_map.h" |
| +#include "native_client/src/trusted/service_runtime/osx/mach_thread_trusted_state.h" |
| #include "native_client/src/trusted/service_runtime/sel_ldr.h" |
| #include "native_client/src/trusted/service_runtime/sel_rt.h" |
| -/* Only handle x86_32 for now. */ |
| -#if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 |
| +#if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 |
| /* |
| @@ -87,31 +89,64 @@ |
| } |
| } |
| +#if NACL_BUILD_SUBARCH == 32 |
| + |
| +#define NATIVE_x86_THREAD_STATE x86_THREAD_STATE32 |
| +#define TSx ts32 |
| + |
| +#define TS_xCX TSx.__ecx |
|
Mark Seaborn
2013/02/14 23:55:02
I'm not overly keen on adding macros for accessing
|
| +#define TS_xBP TSx.__ebp |
| +#define TS_xSP TSx.__esp |
| +#define TS_SS TSx.__ss |
| +#define TS_xFLAGS TSx.__eflags |
| +#define TS_xIP TSx.__eip |
| +#define TS_CS TSx.__cs |
| +#define TS_DS TSx.__ds |
| +#define TS_ES TSx.__es |
| +#define TS_GS TSx.__gs |
| + |
| +#elif NACL_BUILD_SUBARCH == 64 |
| + |
| +#define NATIVE_x86_THREAD_STATE x86_THREAD_STATE64 |
| +#define TSx ts64 |
| + |
| +#define TS_xDI TSx.__rdi |
| +#define TS_xBP TSx.__rbp |
| +#define TS_xSP TSx.__rsp |
| +#define TS_xIP TSx.__rip |
| +#define TS_xFLAGS TSx.__rflags |
| + |
| +#endif /* NACL_BUILD_SUBARCH */ |
| + |
| static int HandleException(mach_port_t thread_port, |
| exception_type_t exception, int *is_untrusted) { |
| mach_msg_type_number_t size; |
| x86_thread_state_t regs; |
| kern_return_t result; |
| - uint16_t trusted_cs = NaClGetGlobalCs(); |
| - uint16_t trusted_ds = NaClGetGlobalDs(); |
| uint32_t nacl_thread_index; |
| struct NaClApp *nap; |
| struct NaClAppThread *natp; |
| struct NaClExceptionFrame frame; |
| - uintptr_t frame_addr_user; |
| + uint32_t frame_addr_user; |
| uintptr_t frame_addr_sys; |
| +#if NACL_BUILD_SUBARCH == 32 |
| + uint16_t trusted_cs = NaClGetGlobalCs(); |
| + uint16_t trusted_ds = NaClGetGlobalDs(); |
| +#endif |
| /* Assume untrusted crash until we know otherwise. */ |
| *is_untrusted = TRUE; |
| /* Capture the register state of the 'excepting' thread. */ |
| - size = sizeof(regs) / sizeof(natural_t); |
| + size = x86_THREAD_STATE_COUNT; |
| result = thread_get_state(thread_port, x86_THREAD_STATE, |
| - (void *) ®s, &size); |
| + (thread_state_t) ®s, &size); |
| if (result != KERN_SUCCESS) { |
| return 0; |
| } |
| + CHECK(regs.tsh.flavor == NATIVE_x86_THREAD_STATE); |
| +#if NACL_BUILD_SUBARCH == 32 |
| /* |
| * If trusted_cs is 0 (which is not a usable segment selector), the |
| * sandbox has not been initialised yet, so there can be no untrusted |
| @@ -129,15 +164,15 @@ |
| * the last thing to change when switching into untrusted code. We need |
| * tests to vet this. |
| */ |
| - if (regs.uts.ts32.__cs == trusted_cs) { |
| + if (regs.uts.TS_CS == trusted_cs) { |
| /* |
| * If we are single-stepping, allow NaClSwitchRemainingRegsViaECX() |
| * to continue in order to restore control to untrusted code. |
| */ |
| if (exception == EXC_BREAKPOINT && |
| - (regs.uts.ts32.__eflags & NACL_X86_TRAP_FLAG) != 0 && |
| - regs.uts.ts32.__eip >= (uintptr_t) NaClSwitchRemainingRegsViaECX && |
| - regs.uts.ts32.__eip < (uintptr_t) NaClSwitchRemainingRegsAsmEnd) { |
| + (regs.uts.TS_xFLAGS & NACL_X86_TRAP_FLAG) != 0 && |
| + regs.uts.TS_xIP >= (uintptr_t) NaClSwitchRemainingRegsViaECX && |
| + regs.uts.TS_xIP < (uintptr_t) NaClSwitchRemainingRegsAsmEnd) { |
| return 1; |
| } |
| *is_untrusted = FALSE; |
| @@ -149,28 +184,53 @@ |
| * from %gs >> 3. |
| * TODO(bradnelson): Migrate that knowledge to a single shared location. |
| */ |
| - nacl_thread_index = regs.uts.ts32.__gs >> 3; |
| + nacl_thread_index = regs.uts.TS_GS >> 3; |
| +#elif NACL_BUILD_SUBARCH == 64 |
| + nacl_thread_index = NaClGetThreadIndexForMachThread(thread_port); |
| + if (nacl_thread_index == NACL_TLS_INDEX_INVALID) { |
| + *is_untrusted = FALSE; |
| + return 0; |
| + } |
| +#endif |
| + |
| natp = NaClAppThreadGetFromIndex(nacl_thread_index); |
| nap = natp->nap; |
| +#if NACL_BUILD_SUBARCH == 64 |
|
Mark Seaborn
2013/02/14 23:55:02
It looks like you don't need this #if, and your in
|
| + *is_untrusted = NaClMachThreadStateIsInUntrusted(®s, nacl_thread_index); |
| + /* |
| + * If trusted code accidentally jumped to untrusted code, don't let the |
| + * untrusted exception handler take over. |
| + */ |
| + if (*is_untrusted && |
| + (natp->suspend_state & NACL_APP_THREAD_UNTRUSTED) == 0) { |
| + *is_untrusted = 0; |
| + } |
| + if (!*is_untrusted) { |
| + return 0; |
| + } |
| +#endif |
| + |
| if (nap->enable_faulted_thread_queue) { |
| +#if NACL_BUILD_SUBARCH == 32 |
| /* |
| * If we are single-stepping, step through until we reach untrusted code. |
| */ |
| if (exception == EXC_BREAKPOINT && |
| - (regs.uts.ts32.__eflags & NACL_X86_TRAP_FLAG) != 0) { |
| - if (regs.uts.ts32.__eip >= nap->all_regs_springboard.start_addr && |
| - regs.uts.ts32.__eip < nap->all_regs_springboard.end_addr) { |
| + (regs.uts.TS_xFLAGS & NACL_X86_TRAP_FLAG) != 0) { |
| + if (regs.uts.TS_xIP >= nap->all_regs_springboard.start_addr && |
| + regs.uts.TS_xIP < nap->all_regs_springboard.end_addr) { |
| return 1; |
| } |
| /* |
| * Step through the instruction we have been asked to restore |
| * control to. |
| */ |
| - if (regs.uts.ts32.__eip == natp->user.gs_segment.new_prog_ctr) { |
| + if (regs.uts.TS_xIP == natp->user.gs_segment.new_prog_ctr) { |
| return 1; |
| } |
| } |
| +#endif |
| /* |
| * Increment the kernel's thread suspension count so that the |
| @@ -192,35 +252,12 @@ |
| return 1; |
| } |
| - /* |
| - * Ignore all but bad accesses for now. |
| - * TODO(bradnelson): eventually consider these too: |
| - * EXC_BAD_INSTRUCTION |
| - * EXC_ARITHMETIC |
| - * EXC_BREAKPOINT |
| - */ |
| - if (exception != EXC_BAD_ACCESS) { |
| - return 0; |
| - } |
| - |
| - /* Don't handle it if the exception flag is set. */ |
| - if (natp->exception_flag) { |
| - return 0; |
| - } |
| - /* Set the flag. */ |
| - natp->exception_flag = 1; |
| - |
| - /* Don't handle if no exception handler is set. */ |
| - if (nap->exception_handler == 0) { |
| - return 0; |
| - } |
| - |
| /* Get location of exception stack frame. */ |
| if (natp->exception_stack) { |
| frame_addr_user = natp->exception_stack; |
| } else { |
| /* If not set default to user stack. */ |
| - frame_addr_user = regs.uts.ts32.__esp; |
| + frame_addr_user = regs.uts.TS_xSP - NACL_STACK_RED_ZONE; |
| } |
| /* Align stack frame properly. */ |
| @@ -236,13 +273,38 @@ |
| return 0; |
| } |
| + /* |
| + * Ignore all but bad accesses for now. |
| + * TODO(bradnelson): eventually consider these too: |
| + * EXC_BAD_INSTRUCTION |
| + * EXC_ARITHMETIC |
| + * EXC_BREAKPOINT |
| + */ |
| + if (exception != EXC_BAD_ACCESS) { |
| + return 0; |
| + } |
| + |
| + /* Don't handle if no exception handler is set. */ |
| + if (nap->exception_handler == 0) { |
|
Mark Seaborn
2013/02/14 23:55:02
I can see why you reordered this before checking e
Mark Mentovai
2013/02/15 17:36:42
Mark Seaborn wrote:
|
| + return 0; |
| + } |
| + |
| + /* Don't handle it if the exception flag is set. */ |
| + if (natp->exception_flag) { |
| + return 0; |
| + } |
| + /* Set the flag. */ |
| + natp->exception_flag = 1; |
| + |
| /* Set up the stack frame for the handler invocation. */ |
| frame.return_addr = 0; |
| + frame.context.prog_ctr = regs.uts.TS_xIP; |
| + frame.context.stack_ptr = regs.uts.TS_xSP; |
| + frame.context.frame_ptr = regs.uts.TS_xBP; |
| +#if NACL_BUILD_SUBARCH == 32 |
| frame.context_ptr = frame_addr_user + |
| offsetof(struct NaClExceptionFrame, context); |
| - frame.context.prog_ctr = regs.uts.ts32.__eip; |
| - frame.context.stack_ptr = regs.uts.ts32.__esp; |
| - frame.context.frame_ptr = regs.uts.ts32.__ebp; |
| +#endif |
| /* |
| * Write the stack frame into untrusted address space. We do not |
| @@ -259,10 +321,8 @@ |
| } |
| /* Set up thread context to resume at handler. */ |
| - natp->user.new_prog_ctr = nap->exception_handler; |
| - natp->user.stack_ptr = frame_addr_user; |
| /* TODO(bradnelson): put all registers in some default state. */ |
| - |
| +#if NACL_BUILD_SUBARCH == 32 |
| /* |
| * Put registers in right place to land at NaClSwitchNoSSEViaECX |
| * This is required because: |
| @@ -276,15 +336,26 @@ |
| * Instead we call a variant of NaClSwitchNoSSE which takes a pointer |
| * to the thread user context in %ecx. |
| */ |
| - regs.uts.ts32.__eip = (uint32_t) &NaClSwitchNoSSEViaECX; |
| - regs.uts.ts32.__cs = trusted_cs; |
| - regs.uts.ts32.__ecx = (uint32_t) &natp->user; |
| - regs.uts.ts32.__ds = trusted_ds; |
| - regs.uts.ts32.__es = trusted_ds; /* just for good measure */ |
| - regs.uts.ts32.__ss = trusted_ds; /* just for good measure */ |
| - regs.uts.ts32.__eflags &= ~NACL_X86_DIRECTION_FLAG; |
| + natp->user.new_prog_ctr = nap->exception_handler; |
| + natp->user.stack_ptr = frame_addr_user; |
| + regs.uts.TS_xIP = (uint32_t) &NaClSwitchNoSSEViaECX; |
| + regs.uts.TS_CS = trusted_cs; |
| + regs.uts.TS_xCX = (uint32_t) &natp->user; |
| + regs.uts.TS_DS = trusted_ds; |
| + regs.uts.TS_ES = trusted_ds; /* just for good measure */ |
| + regs.uts.TS_SS = trusted_ds; /* just for good measure */ |
| +#elif NACL_BUILD_SUBARCH == 64 |
| + regs.uts.TS_xIP = NaClUserToSys(nap, nap->exception_handler); |
| + regs.uts.TS_xSP = frame_addr_sys; |
| + regs.uts.TS_xBP = nap->mem_start; |
| + |
| + /* Argument 1 */ |
| + regs.uts.TS_xDI = frame_addr_user + |
| + offsetof(struct NaClExceptionFrame, context); |
| +#endif |
| + regs.uts.TS_xFLAGS &= ~NACL_X86_DIRECTION_FLAG; |
| result = thread_set_state(thread_port, x86_THREAD_STATE, |
| - (void *) ®s, size); |
| + (thread_state_t) ®s, size); |
| if (result != KERN_SUCCESS) { |
| return 0; |
| } |
| @@ -570,10 +641,4 @@ |
| return FALSE; |
| } |
| -#else /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 */ |
| - |
| -int NaClInterceptMachExceptions(void) { |
| - return FALSE; |
| -} |
| - |
| -#endif /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 */ |
| +#endif /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 */ |