int NaClMachThreadIsInUntrusted(mach_port_t thread_port) { x86_thread_state_t state; thread_state_t statep = (thread_state_t) &state; mach_msg_type_number_t size = x86_THREAD_STATE_COUNT; kern_return_t kr; uint32_t nacl_thread_index; kr = thread_get_state(thread_port, x86_THREAD_STATE, statep, &size); if (kr != KERN_SUCCESS) { NaClLog(LOG_FATAL, "NaClMachThreadIsInUntrusted: " "thread_get_state() failed with error %i\n", kr); } CHECK(kr == KERN_SUCCESS); #if NACL_BUILD_SUBARCH == 32 CHECK(state.tsh.flavor == x86_THREAD_STATE32); nacl_thread_index = state.uts.ts32.__gs >> 3; #elif NACL_BUILD_SUBARCH == 64 nacl_thread_index = NaClGetThreadIndexForMachThread(thread_port); /* * If the thread isn't known to Native Client, it's not untrusted (at least * not by Native Client.) */ if (nacl_thread_index == NACL_TLS_INDEX_INVALID) { return 0; } #endif return NaClMachThreadStateIsInUntrusted(&state, nacl_thread_index); }
void NaClSetCurrentMachThreadForThreadIndex(uint32_t nacl_thread_index) { /* * This implementation relies on the Mach port for the thread stored by the * pthread library, and assumes that the pthread library does not close and * re-acquire the Mach port for the thread. If that happens, Mach could * theoretically assign the port a different number in the process' port * table. This approach avoids having to deal with ownership of the port and * the system call overhad to obtain and deallocate it as would be the case * with mach_thread_self(). * * When used by the Mach exception handler, this also assumes that the * thread port number when received for an exception will match the port * stored in the mach_threads table. This is guaranteed by how the kernel * coalesces ports in a single port namespace. (A task, or process, is a * single port namespace.) * * An alternative implementation that works on Mac OS X 10.6 or higher is to * use pthread_threadid_np() to obtain a thread ID to use as the key for * this thread map. Such thread IDs are unique system-wide. An exception * handler can find the thread ID for a Mach thread by calling thread_info() * with flavor THREAD_IDENTIFIER_INFO. This approach is not used here * because of the added system call overhead at exception time. */ mach_port_t mach_thread = pthread_mach_thread_np(pthread_self()); CHECK(mach_thread != MACH_PORT_NULL); DCHECK(nacl_thread_index > NACL_TLS_INDEX_INVALID && nacl_thread_index < NACL_THREAD_MAX); DCHECK(mach_threads[nacl_thread_index] == MACH_PORT_NULL); DCHECK(NaClGetThreadIndexForMachThread(mach_thread) == NACL_TLS_INDEX_INVALID); mach_threads[nacl_thread_index] = mach_thread; }
void NaClClearMachThreadForThreadIndex(uint32_t nacl_thread_index) { mach_port_t mach_thread = mach_threads[nacl_thread_index]; DCHECK(nacl_thread_index > NACL_TLS_INDEX_INVALID && nacl_thread_index < NACL_THREAD_MAX); DCHECK(mach_thread == pthread_mach_thread_np(pthread_self())); mach_threads[nacl_thread_index] = MACH_PORT_NULL; DCHECK(NaClGetThreadIndexForMachThread(mach_thread) == NACL_TLS_INDEX_INVALID); }