diff options
author | comex | 2015-02-18 02:22:36 -0500 |
---|---|---|
committer | comex | 2015-02-18 02:22:36 -0500 |
commit | 7c26a1964d2d2e54f87d9c42735f6c99b546abd4 (patch) | |
tree | f50838e492aa101a4d87e6ef01d1dc2611f32f97 /lib/darwin/stop-other-threads.c | |
parent | more fixes (diff) | |
download | substitute-7c26a1964d2d2e54f87d9c42735f6c99b546abd4.tar.gz |
Fix hook-function:
- Thread stoppage is now complemented by sigaction to catch injected
threads (sigaction is not used exclusively because the rest of the
program could be trying to use sigaction itself in the meantime - this
is a real thing, ask Dolphin)
- mprotect is no longer used due to max_protection possibly getting in
the way; instead, a copy is created and mapped onto the original.
Diffstat (limited to 'lib/darwin/stop-other-threads.c')
-rw-r--r-- | lib/darwin/stop-other-threads.c | 163 |
1 files changed, 0 insertions, 163 deletions
diff --git a/lib/darwin/stop-other-threads.c b/lib/darwin/stop-other-threads.c deleted file mode 100644 index ff239f3..0000000 --- a/lib/darwin/stop-other-threads.c +++ /dev/null @@ -1,163 +0,0 @@ -#include "substitute.h" -#include "substitute-internal.h" -#include "darwin/mach-decls.h" -#include "stop-other-threads.h" -#include "cbit/htab.h" -#include <pthread.h> -#include <mach/mach.h> - -#define port_hash(portp) (*(portp)) -#define port_eq(port1p, port2p) (*(port1p) == *(port2p)) -#define port_null(portp) (*(portp) == MACH_PORT_NULL) -DECL_STATIC_HTAB_KEY(mach_port_t, mach_port_t, port_hash, port_eq, port_null, 0); -struct empty {}; -DECL_HTAB(mach_port_set, mach_port_t, struct empty); - -static bool apply_one_pcp(mach_port_t thread, - uintptr_t (*callback)(void *ctx, uintptr_t pc), - void *ctx) { - int flavor; -#if defined(__x86_64__) - struct _x86_thread_state_64 state; - flavor = _x86_thread_state_64_flavor; -#elif defined(__i386__) - struct _x86_thread_state_32 state; - flavor = _x86_thread_state_32_flavor; -#elif defined(__arm__) - struct _arm_thread_state_32 state; - flavor = _arm_thread_state_32_flavor; -#elif defined(__arm64__) - struct _arm_thread_state_64 state; - flavor = _arm_thread_state_64_flavor; -#else - #error ? -#endif - - mach_msg_type_number_t real_cnt = sizeof(state) / sizeof(int); - mach_msg_type_number_t cnt = real_cnt; - kern_return_t kr = thread_get_state(thread, flavor, (thread_state_t) &state, &cnt); - if (kr || cnt != real_cnt) - return false; - - uintptr_t *pcp; -#if defined(__x86_64__) - pcp = (uintptr_t *) &state.rip; -#elif defined(__i386__) - pcp = (uintptr_t *) &state.eip; -#elif defined(__arm__) || defined(__arm64__) - pcp = (uintptr_t *) &state.pc; -#endif - uintptr_t old = *pcp; -#ifdef __arm__ - /* thumb */ - if (state.cpsr & 0x20) - old |= 1; -#endif - uintptr_t new = callback(ctx, *pcp); - if (new != old) { - *pcp = new; -#ifdef __arm__ - *pcp &= ~1; - state.cpsr = (state.cpsr & ~0x20) | ((new & 1) * 0x20); -#endif - kr = thread_set_state(thread, flavor, (thread_state_t) &state, real_cnt); - if (kr) - return false; - } - return true; -} - -int stop_other_threads(void **token_ptr) { - if (!pthread_main_np()) - return SUBSTITUTE_ERR_NOT_ON_MAIN_THREAD; - - int ret; - mach_port_t self = mach_thread_self(); - - /* The following shenanigans are for catching any new threads that are - * created while we're looping, without suspending anything twice. Keep - * looping until only threads we already suspended before this loop are - * there. */ - HTAB_STORAGE(mach_port_set) *hs = malloc(sizeof(*hs)); - HTAB_STORAGE_INIT(hs, mach_port_set); - struct htab_mach_port_set *suspended_set = &hs->h; - - thread_act_array_t ports = 0; - mach_msg_type_number_t nports = 0; - - bool got_new = true; - while (got_new) { - got_new = false; - - kern_return_t kr = task_threads(mach_task_self(), &ports, &nports); - if (kr) { /* ouch */ - ret = SUBSTITUTE_ERR_ADJUSTING_THREADS; - goto fail; - } - - for (mach_msg_type_number_t i = 0; i < nports; i++) { - mach_port_t port = ports[i]; - struct htab_bucket_mach_port_set *bucket; - if (port == self || - (bucket = htab_setbucket_mach_port_set(suspended_set, &port), - bucket->key)) { - /* already suspended, ignore */ - mach_port_deallocate(mach_task_self(), port); - } else { - got_new = true; - kr = thread_suspend(port); - if (kr == KERN_TERMINATED) { - /* too late */ - mach_port_deallocate(mach_task_self(), port); - } else if (kr) { - ret = SUBSTITUTE_ERR_ADJUSTING_THREADS; - for (; i < nports; i++) - mach_port_deallocate(mach_task_self(), ports[i]); - vm_deallocate(mach_task_self(), (vm_address_t) ports, - nports * sizeof(*ports)); - goto fail; - } - bucket->key = port; - } - } - vm_deallocate(mach_task_self(), (vm_address_t) ports, - nports * sizeof(*ports)); - } - - /* Success - keep the set around for when we're done. */ - *token_ptr = suspended_set; - return SUBSTITUTE_OK; - -fail: - resume_other_threads(suspended_set); - return ret; -} - -int apply_pc_patch_callback(void *token, - uintptr_t (*pc_patch_callback)(void *ctx, uintptr_t pc), - void *ctx) { - struct htab_mach_port_set *suspended_set = token; - int ret = SUBSTITUTE_OK; - HTAB_FOREACH(suspended_set, mach_port_t *threadp, - UNUSED struct empty *_, - mach_port_set) { - if (!apply_one_pcp(*threadp, pc_patch_callback, ctx)) { - ret = SUBSTITUTE_ERR_ADJUSTING_THREADS; - break; - } - } - return ret; -} - -int resume_other_threads(void *token) { - struct htab_mach_port_set *suspended_set = token; - HTAB_FOREACH(suspended_set, mach_port_t *threadp, - UNUSED struct empty *_, - mach_port_set) { - thread_resume(*threadp); - mach_port_deallocate(mach_task_self(), *threadp); - } - htab_free_storage_mach_port_set(suspended_set); - free(suspended_set); - return SUBSTITUTE_OK; /* eh */ -} |