Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/nacl_tls.h" | |
| 30 #include "native_client/src/trusted/service_runtime/osx/mach_thread_map.h" | |
| 31 #include "native_client/src/trusted/service_runtime/osx/mach_thread_trusted_stat e.h" | |
| 29 #include "native_client/src/trusted/service_runtime/sel_ldr.h" | 32 #include "native_client/src/trusted/service_runtime/sel_ldr.h" |
| 30 #include "native_client/src/trusted/service_runtime/sel_rt.h" | 33 #include "native_client/src/trusted/service_runtime/sel_rt.h" |
| 31 | 34 |
| 32 /* Only handle x86_32 for now. */ | 35 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 |
| 33 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 | |
| 34 | 36 |
| 35 | 37 |
| 36 /* | 38 /* |
| 37 * MIG generated message pump from /usr/include/mach/exc.defs | 39 * MIG generated message pump from /usr/include/mach/exc.defs |
| 38 * Tweaked to place in an isolated namespace. | 40 * Tweaked to place in an isolated namespace. |
| 39 */ | 41 */ |
| 40 boolean_t nacl_exc_server( | 42 boolean_t nacl_exc_server( |
| 41 mach_msg_header_t *InHeadP, | 43 mach_msg_header_t *InHeadP, |
| 42 mach_msg_header_t *OutHeadP); | 44 mach_msg_header_t *OutHeadP); |
| 43 | 45 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 80 } | 82 } |
| 81 } | 83 } |
| 82 | 84 |
| 83 static void FireDebugStubEvent(int pipe_fd) { | 85 static void FireDebugStubEvent(int pipe_fd) { |
| 84 char buf = 0; | 86 char buf = 0; |
| 85 if (write(pipe_fd, &buf, sizeof(buf)) != sizeof(buf)) { | 87 if (write(pipe_fd, &buf, sizeof(buf)) != sizeof(buf)) { |
| 86 NaClLog(LOG_FATAL, "FireDebugStubEvent: Can't send debug stub event\n"); | 88 NaClLog(LOG_FATAL, "FireDebugStubEvent: Can't send debug stub event\n"); |
| 87 } | 89 } |
| 88 } | 90 } |
| 89 | 91 |
| 92 #if NACL_BUILD_SUBARCH == 32 | |
| 93 | |
| 94 #define NATIVE_x86_THREAD_STATE x86_THREAD_STATE32 | |
| 95 #define TSx ts32 | |
| 96 | |
| 97 #define TS_xCX TSx.__ecx | |
|
Mark Seaborn
2013/02/14 23:55:02
I'm not overly keen on adding macros for accessing
| |
| 98 #define TS_xBP TSx.__ebp | |
| 99 #define TS_xSP TSx.__esp | |
| 100 #define TS_SS TSx.__ss | |
| 101 #define TS_xFLAGS TSx.__eflags | |
| 102 #define TS_xIP TSx.__eip | |
| 103 #define TS_CS TSx.__cs | |
| 104 #define TS_DS TSx.__ds | |
| 105 #define TS_ES TSx.__es | |
| 106 #define TS_GS TSx.__gs | |
| 107 | |
| 108 #elif NACL_BUILD_SUBARCH == 64 | |
| 109 | |
| 110 #define NATIVE_x86_THREAD_STATE x86_THREAD_STATE64 | |
| 111 #define TSx ts64 | |
| 112 | |
| 113 #define TS_xDI TSx.__rdi | |
| 114 #define TS_xBP TSx.__rbp | |
| 115 #define TS_xSP TSx.__rsp | |
| 116 #define TS_xIP TSx.__rip | |
| 117 #define TS_xFLAGS TSx.__rflags | |
| 118 | |
| 119 #endif /* NACL_BUILD_SUBARCH */ | |
| 120 | |
| 90 static int HandleException(mach_port_t thread_port, | 121 static int HandleException(mach_port_t thread_port, |
| 91 exception_type_t exception, int *is_untrusted) { | 122 exception_type_t exception, int *is_untrusted) { |
| 92 mach_msg_type_number_t size; | 123 mach_msg_type_number_t size; |
| 93 x86_thread_state_t regs; | 124 x86_thread_state_t regs; |
| 94 kern_return_t result; | 125 kern_return_t result; |
| 95 uint16_t trusted_cs = NaClGetGlobalCs(); | |
| 96 uint16_t trusted_ds = NaClGetGlobalDs(); | |
| 97 uint32_t nacl_thread_index; | 126 uint32_t nacl_thread_index; |
| 98 struct NaClApp *nap; | 127 struct NaClApp *nap; |
| 99 struct NaClAppThread *natp; | 128 struct NaClAppThread *natp; |
| 100 struct NaClExceptionFrame frame; | 129 struct NaClExceptionFrame frame; |
| 101 uintptr_t frame_addr_user; | 130 uint32_t frame_addr_user; |
| 102 uintptr_t frame_addr_sys; | 131 uintptr_t frame_addr_sys; |
| 132 #if NACL_BUILD_SUBARCH == 32 | |
| 133 uint16_t trusted_cs = NaClGetGlobalCs(); | |
| 134 uint16_t trusted_ds = NaClGetGlobalDs(); | |
| 135 #endif | |
| 103 | 136 |
| 104 /* Assume untrusted crash until we know otherwise. */ | 137 /* Assume untrusted crash until we know otherwise. */ |
| 105 *is_untrusted = TRUE; | 138 *is_untrusted = TRUE; |
| 106 | 139 |
| 107 /* Capture the register state of the 'excepting' thread. */ | 140 /* Capture the register state of the 'excepting' thread. */ |
| 108 size = sizeof(regs) / sizeof(natural_t); | 141 size = x86_THREAD_STATE_COUNT; |
| 109 result = thread_get_state(thread_port, x86_THREAD_STATE, | 142 result = thread_get_state(thread_port, x86_THREAD_STATE, |
| 110 (void *) ®s, &size); | 143 (thread_state_t) ®s, &size); |
| 111 if (result != KERN_SUCCESS) { | 144 if (result != KERN_SUCCESS) { |
| 112 return 0; | 145 return 0; |
| 113 } | 146 } |
| 147 CHECK(regs.tsh.flavor == NATIVE_x86_THREAD_STATE); | |
| 114 | 148 |
| 149 #if NACL_BUILD_SUBARCH == 32 | |
| 115 /* | 150 /* |
| 116 * If trusted_cs is 0 (which is not a usable segment selector), the | 151 * 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 | 152 * sandbox has not been initialised yet, so there can be no untrusted |
| 118 * code running. | 153 * code running. |
| 119 */ | 154 */ |
| 120 if (trusted_cs == 0) { | 155 if (trusted_cs == 0) { |
| 121 *is_untrusted = FALSE; | 156 *is_untrusted = FALSE; |
| 122 return 0; | 157 return 0; |
| 123 } | 158 } |
| 124 | 159 |
| 125 /* | 160 /* |
| 126 * If the current code segment is the trusted one, we aren't in the | 161 * If the current code segment is the trusted one, we aren't in the |
| 127 * sandbox. | 162 * sandbox. |
| 128 * TODO(bradnelson): This makes the potentially false assumption that cs is | 163 * TODO(bradnelson): This makes the potentially false assumption that cs is |
| 129 * the last thing to change when switching into untrusted code. We need | 164 * the last thing to change when switching into untrusted code. We need |
| 130 * tests to vet this. | 165 * tests to vet this. |
| 131 */ | 166 */ |
| 132 if (regs.uts.ts32.__cs == trusted_cs) { | 167 if (regs.uts.TS_CS == trusted_cs) { |
| 133 /* | 168 /* |
| 134 * If we are single-stepping, allow NaClSwitchRemainingRegsViaECX() | 169 * If we are single-stepping, allow NaClSwitchRemainingRegsViaECX() |
| 135 * to continue in order to restore control to untrusted code. | 170 * to continue in order to restore control to untrusted code. |
| 136 */ | 171 */ |
| 137 if (exception == EXC_BREAKPOINT && | 172 if (exception == EXC_BREAKPOINT && |
| 138 (regs.uts.ts32.__eflags & NACL_X86_TRAP_FLAG) != 0 && | 173 (regs.uts.TS_xFLAGS & NACL_X86_TRAP_FLAG) != 0 && |
| 139 regs.uts.ts32.__eip >= (uintptr_t) NaClSwitchRemainingRegsViaECX && | 174 regs.uts.TS_xIP >= (uintptr_t) NaClSwitchRemainingRegsViaECX && |
| 140 regs.uts.ts32.__eip < (uintptr_t) NaClSwitchRemainingRegsAsmEnd) { | 175 regs.uts.TS_xIP < (uintptr_t) NaClSwitchRemainingRegsAsmEnd) { |
| 141 return 1; | 176 return 1; |
| 142 } | 177 } |
| 143 *is_untrusted = FALSE; | 178 *is_untrusted = FALSE; |
| 144 return 0; | 179 return 0; |
| 145 } | 180 } |
| 146 | 181 |
| 147 /* | 182 /* |
| 148 * We can get the thread index from the segment selector used for TLS | 183 * We can get the thread index from the segment selector used for TLS |
| 149 * from %gs >> 3. | 184 * from %gs >> 3. |
| 150 * TODO(bradnelson): Migrate that knowledge to a single shared location. | 185 * TODO(bradnelson): Migrate that knowledge to a single shared location. |
| 151 */ | 186 */ |
| 152 nacl_thread_index = regs.uts.ts32.__gs >> 3; | 187 nacl_thread_index = regs.uts.TS_GS >> 3; |
| 188 #elif NACL_BUILD_SUBARCH == 64 | |
| 189 nacl_thread_index = NaClGetThreadIndexForMachThread(thread_port); | |
| 190 if (nacl_thread_index == NACL_TLS_INDEX_INVALID) { | |
| 191 *is_untrusted = FALSE; | |
| 192 return 0; | |
| 193 } | |
| 194 #endif | |
| 195 | |
| 153 natp = NaClAppThreadGetFromIndex(nacl_thread_index); | 196 natp = NaClAppThreadGetFromIndex(nacl_thread_index); |
| 154 nap = natp->nap; | 197 nap = natp->nap; |
| 155 | 198 |
| 199 #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
| |
| 200 *is_untrusted = NaClMachThreadStateIsInUntrusted(®s, nacl_thread_index); | |
| 201 /* | |
| 202 * If trusted code accidentally jumped to untrusted code, don't let the | |
| 203 * untrusted exception handler take over. | |
| 204 */ | |
| 205 if (*is_untrusted && | |
| 206 (natp->suspend_state & NACL_APP_THREAD_UNTRUSTED) == 0) { | |
| 207 *is_untrusted = 0; | |
| 208 } | |
| 209 if (!*is_untrusted) { | |
| 210 return 0; | |
| 211 } | |
| 212 #endif | |
| 213 | |
| 156 if (nap->enable_faulted_thread_queue) { | 214 if (nap->enable_faulted_thread_queue) { |
| 215 #if NACL_BUILD_SUBARCH == 32 | |
| 157 /* | 216 /* |
| 158 * If we are single-stepping, step through until we reach untrusted code. | 217 * If we are single-stepping, step through until we reach untrusted code. |
| 159 */ | 218 */ |
| 160 if (exception == EXC_BREAKPOINT && | 219 if (exception == EXC_BREAKPOINT && |
| 161 (regs.uts.ts32.__eflags & NACL_X86_TRAP_FLAG) != 0) { | 220 (regs.uts.TS_xFLAGS & NACL_X86_TRAP_FLAG) != 0) { |
| 162 if (regs.uts.ts32.__eip >= nap->all_regs_springboard.start_addr && | 221 if (regs.uts.TS_xIP >= nap->all_regs_springboard.start_addr && |
| 163 regs.uts.ts32.__eip < nap->all_regs_springboard.end_addr) { | 222 regs.uts.TS_xIP < nap->all_regs_springboard.end_addr) { |
| 164 return 1; | 223 return 1; |
| 165 } | 224 } |
| 166 /* | 225 /* |
| 167 * Step through the instruction we have been asked to restore | 226 * Step through the instruction we have been asked to restore |
| 168 * control to. | 227 * control to. |
| 169 */ | 228 */ |
| 170 if (regs.uts.ts32.__eip == natp->user.gs_segment.new_prog_ctr) { | 229 if (regs.uts.TS_xIP == natp->user.gs_segment.new_prog_ctr) { |
| 171 return 1; | 230 return 1; |
| 172 } | 231 } |
| 173 } | 232 } |
| 233 #endif | |
| 174 | 234 |
| 175 /* | 235 /* |
| 176 * Increment the kernel's thread suspension count so that the | 236 * Increment the kernel's thread suspension count so that the |
| 177 * thread remains suspended after we return. | 237 * thread remains suspended after we return. |
| 178 */ | 238 */ |
| 179 result = thread_suspend(thread_port); | 239 result = thread_suspend(thread_port); |
| 180 if (result != KERN_SUCCESS) { | 240 if (result != KERN_SUCCESS) { |
| 181 NaClLog(LOG_FATAL, "HandleException: thread_suspend() call failed\n"); | 241 NaClLog(LOG_FATAL, "HandleException: thread_suspend() call failed\n"); |
| 182 } | 242 } |
| 183 /* | 243 /* |
| 184 * Notify the handler running on another thread. This must happen | 244 * Notify the handler running on another thread. This must happen |
| 185 * after the thread_suspend() call, otherwise the handler might | 245 * after the thread_suspend() call, otherwise the handler might |
| 186 * receive the notification and attempt to decrement the thread's | 246 * receive the notification and attempt to decrement the thread's |
| 187 * suspension count before we have incremented it. | 247 * suspension count before we have incremented it. |
| 188 */ | 248 */ |
| 189 natp->fault_signal = ExceptionCodeToNaClSignalNumber(exception); | 249 natp->fault_signal = ExceptionCodeToNaClSignalNumber(exception); |
| 190 AtomicIncrement(&nap->faulted_thread_count, 1); | 250 AtomicIncrement(&nap->faulted_thread_count, 1); |
| 191 FireDebugStubEvent(nap->faulted_thread_fd_write); | 251 FireDebugStubEvent(nap->faulted_thread_fd_write); |
| 192 return 1; | 252 return 1; |
| 193 } | 253 } |
| 194 | 254 |
| 195 /* | |
| 196 * Ignore all but bad accesses for now. | |
| 197 * TODO(bradnelson): eventually consider these too: | |
| 198 * EXC_BAD_INSTRUCTION | |
| 199 * EXC_ARITHMETIC | |
| 200 * EXC_BREAKPOINT | |
| 201 */ | |
| 202 if (exception != EXC_BAD_ACCESS) { | |
| 203 return 0; | |
| 204 } | |
| 205 | |
| 206 /* Don't handle it if the exception flag is set. */ | |
| 207 if (natp->exception_flag) { | |
| 208 return 0; | |
| 209 } | |
| 210 /* Set the flag. */ | |
| 211 natp->exception_flag = 1; | |
| 212 | |
| 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. */ | 255 /* Get location of exception stack frame. */ |
| 219 if (natp->exception_stack) { | 256 if (natp->exception_stack) { |
| 220 frame_addr_user = natp->exception_stack; | 257 frame_addr_user = natp->exception_stack; |
| 221 } else { | 258 } else { |
| 222 /* If not set default to user stack. */ | 259 /* If not set default to user stack. */ |
| 223 frame_addr_user = regs.uts.ts32.__esp; | 260 frame_addr_user = regs.uts.TS_xSP - NACL_STACK_RED_ZONE; |
| 224 } | 261 } |
| 225 | 262 |
| 226 /* Align stack frame properly. */ | 263 /* Align stack frame properly. */ |
| 227 frame_addr_user -= | 264 frame_addr_user -= |
| 228 sizeof(struct NaClExceptionFrame) - NACL_STACK_PAD_BELOW_ALIGN; | 265 sizeof(struct NaClExceptionFrame) - NACL_STACK_PAD_BELOW_ALIGN; |
| 229 frame_addr_user &= ~NACL_STACK_ALIGN_MASK; | 266 frame_addr_user &= ~NACL_STACK_ALIGN_MASK; |
| 230 frame_addr_user -= NACL_STACK_PAD_BELOW_ALIGN; | 267 frame_addr_user -= NACL_STACK_PAD_BELOW_ALIGN; |
| 231 | 268 |
| 232 /* Convert from user to system space. */ | 269 /* Convert from user to system space. */ |
| 233 frame_addr_sys = NaClUserToSysAddrRange( | 270 frame_addr_sys = NaClUserToSysAddrRange( |
| 234 nap, frame_addr_user, sizeof(struct NaClExceptionFrame)); | 271 nap, frame_addr_user, sizeof(struct NaClExceptionFrame)); |
| 235 if (frame_addr_sys == kNaClBadAddress) { | 272 if (frame_addr_sys == kNaClBadAddress) { |
| 236 return 0; | 273 return 0; |
| 237 } | 274 } |
| 238 | 275 |
| 276 /* | |
| 277 * Ignore all but bad accesses for now. | |
| 278 * TODO(bradnelson): eventually consider these too: | |
| 279 * EXC_BAD_INSTRUCTION | |
| 280 * EXC_ARITHMETIC | |
| 281 * EXC_BREAKPOINT | |
| 282 */ | |
| 283 if (exception != EXC_BAD_ACCESS) { | |
| 284 return 0; | |
| 285 } | |
| 286 | |
| 287 /* Don't handle if no exception handler is set. */ | |
| 288 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:
| |
| 289 return 0; | |
| 290 } | |
| 291 | |
| 292 /* Don't handle it if the exception flag is set. */ | |
| 293 if (natp->exception_flag) { | |
| 294 return 0; | |
| 295 } | |
| 296 /* Set the flag. */ | |
| 297 natp->exception_flag = 1; | |
| 298 | |
| 239 /* Set up the stack frame for the handler invocation. */ | 299 /* Set up the stack frame for the handler invocation. */ |
| 240 frame.return_addr = 0; | 300 frame.return_addr = 0; |
| 301 frame.context.prog_ctr = regs.uts.TS_xIP; | |
| 302 frame.context.stack_ptr = regs.uts.TS_xSP; | |
| 303 frame.context.frame_ptr = regs.uts.TS_xBP; | |
| 304 #if NACL_BUILD_SUBARCH == 32 | |
| 241 frame.context_ptr = frame_addr_user + | 305 frame.context_ptr = frame_addr_user + |
| 242 offsetof(struct NaClExceptionFrame, context); | 306 offsetof(struct NaClExceptionFrame, context); |
| 243 frame.context.prog_ctr = regs.uts.ts32.__eip; | 307 #endif |
| 244 frame.context.stack_ptr = regs.uts.ts32.__esp; | |
| 245 frame.context.frame_ptr = regs.uts.ts32.__ebp; | |
| 246 | 308 |
| 247 /* | 309 /* |
| 248 * Write the stack frame into untrusted address space. We do not | 310 * Write the stack frame into untrusted address space. We do not |
| 249 * write to the memory directly because that will fault if the | 311 * write to the memory directly because that will fault if the |
| 250 * destination location is not writable. Faulting is OK for NaCl | 312 * destination location is not writable. Faulting is OK for NaCl |
| 251 * syscalls, but here we do not want to trigger an exception while | 313 * syscalls, but here we do not want to trigger an exception while |
| 252 * in the exception handler. The overhead of using a Mach system | 314 * in the exception handler. The overhead of using a Mach system |
| 253 * call to write to memory is acceptable here. | 315 * call to write to memory is acceptable here. |
| 254 */ | 316 */ |
| 255 result = mach_vm_write(mach_task_self(), frame_addr_sys, | 317 result = mach_vm_write(mach_task_self(), frame_addr_sys, |
| 256 (uintptr_t) &frame, sizeof(frame)); | 318 (uintptr_t) &frame, sizeof(frame)); |
| 257 if (result != KERN_SUCCESS) { | 319 if (result != KERN_SUCCESS) { |
| 258 return 0; | 320 return 0; |
| 259 } | 321 } |
| 260 | 322 |
| 261 /* Set up thread context to resume at handler. */ | 323 /* Set up thread context to resume at handler. */ |
| 262 natp->user.new_prog_ctr = nap->exception_handler; | |
| 263 natp->user.stack_ptr = frame_addr_user; | |
| 264 /* TODO(bradnelson): put all registers in some default state. */ | 324 /* TODO(bradnelson): put all registers in some default state. */ |
| 265 | 325 #if NACL_BUILD_SUBARCH == 32 |
| 266 /* | 326 /* |
| 267 * Put registers in right place to land at NaClSwitchNoSSEViaECX | 327 * Put registers in right place to land at NaClSwitchNoSSEViaECX |
| 268 * This is required because: | 328 * This is required because: |
| 269 * - For an unknown reason thread_set_state resets %cs to the default | 329 * - For an unknown reason thread_set_state resets %cs to the default |
| 270 * value, even when set to something else, in current XNU versions. | 330 * value, even when set to something else, in current XNU versions. |
| 271 * - An examination of the XNU sources indicates | 331 * - An examination of the XNU sources indicates |
| 272 * that setting the code which state the thread state resets | 332 * that setting the code which state the thread state resets |
| 273 * %cs, %ds, %es, %ss to their default values in some early versions. | 333 * %cs, %ds, %es, %ss to their default values in some early versions. |
| 274 * (For instance: xnu-792.6.22/osfmk/i386/pcb.c:616) | 334 * (For instance: xnu-792.6.22/osfmk/i386/pcb.c:616) |
| 275 * This precludes going directly to the untrusted handler. | 335 * This precludes going directly to the untrusted handler. |
| 276 * Instead we call a variant of NaClSwitchNoSSE which takes a pointer | 336 * Instead we call a variant of NaClSwitchNoSSE which takes a pointer |
| 277 * to the thread user context in %ecx. | 337 * to the thread user context in %ecx. |
| 278 */ | 338 */ |
| 279 regs.uts.ts32.__eip = (uint32_t) &NaClSwitchNoSSEViaECX; | 339 natp->user.new_prog_ctr = nap->exception_handler; |
| 280 regs.uts.ts32.__cs = trusted_cs; | 340 natp->user.stack_ptr = frame_addr_user; |
| 281 regs.uts.ts32.__ecx = (uint32_t) &natp->user; | 341 regs.uts.TS_xIP = (uint32_t) &NaClSwitchNoSSEViaECX; |
| 282 regs.uts.ts32.__ds = trusted_ds; | 342 regs.uts.TS_CS = trusted_cs; |
| 283 regs.uts.ts32.__es = trusted_ds; /* just for good measure */ | 343 regs.uts.TS_xCX = (uint32_t) &natp->user; |
| 284 regs.uts.ts32.__ss = trusted_ds; /* just for good measure */ | 344 regs.uts.TS_DS = trusted_ds; |
| 285 regs.uts.ts32.__eflags &= ~NACL_X86_DIRECTION_FLAG; | 345 regs.uts.TS_ES = trusted_ds; /* just for good measure */ |
| 346 regs.uts.TS_SS = trusted_ds; /* just for good measure */ | |
| 347 #elif NACL_BUILD_SUBARCH == 64 | |
| 348 regs.uts.TS_xIP = NaClUserToSys(nap, nap->exception_handler); | |
| 349 regs.uts.TS_xSP = frame_addr_sys; | |
| 350 regs.uts.TS_xBP = nap->mem_start; | |
| 351 | |
| 352 /* Argument 1 */ | |
| 353 regs.uts.TS_xDI = frame_addr_user + | |
| 354 offsetof(struct NaClExceptionFrame, context); | |
| 355 #endif | |
| 356 regs.uts.TS_xFLAGS &= ~NACL_X86_DIRECTION_FLAG; | |
| 286 result = thread_set_state(thread_port, x86_THREAD_STATE, | 357 result = thread_set_state(thread_port, x86_THREAD_STATE, |
| 287 (void *) ®s, size); | 358 (thread_state_t) ®s, size); |
| 288 if (result != KERN_SUCCESS) { | 359 if (result != KERN_SUCCESS) { |
| 289 return 0; | 360 return 0; |
| 290 } | 361 } |
| 291 | 362 |
| 292 /* Return success, and resume the thread. */ | 363 /* Return success, and resume the thread. */ |
| 293 return 1; | 364 return 1; |
| 294 } | 365 } |
| 295 | 366 |
| 296 | 367 |
| 297 static kern_return_t ForwardException( | 368 static kern_return_t ForwardException( |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 563 failure: | 634 failure: |
| 564 if (data) { | 635 if (data) { |
| 565 if (MACH_PORT_NULL != data->exception_port) { | 636 if (MACH_PORT_NULL != data->exception_port) { |
| 566 mach_port_deallocate(current_task, data->exception_port); | 637 mach_port_deallocate(current_task, data->exception_port); |
| 567 } | 638 } |
| 568 free(data); | 639 free(data); |
| 569 } | 640 } |
| 570 return FALSE; | 641 return FALSE; |
| 571 } | 642 } |
| 572 | 643 |
| 573 #else /* NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 */ | 644 #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 */ | |
| OLD | NEW |