diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | ios-bootstrap/posixspawn-hook.c | 27 | ||||
-rw-r--r-- | ios-bootstrap/unrestrict-me.c | 6 | ||||
-rw-r--r-- | lib/darwin/unrestrict.c | 33 | ||||
-rw-r--r-- | lib/substitute-internal.h | 2 | ||||
-rw-r--r-- | test/test-posixspawn-hook.c | 9 |
6 files changed, 66 insertions, 14 deletions
@@ -106,10 +106,10 @@ out/%.bin: out/%.o Makefile define define_test out/test-$(1): test/test-$(2).[cm]* $(HEADERS) $(GENERATED) Makefile out/libsubstitute.dylib $(3) -g -o $$@ $$< -Ilib -Isubstrate -Lout -lsubstitute + install_name_tool -change /usr/lib/libsubstitute.0.dylib '@executable_path/libsubstitute.dylib' $$@ ifneq (,$(IS_IOS)) ldid -Sent.plist $$@ endif - install_name_tool -change /usr/lib/libsubstitute.0.dylib '@executable_path/libsubstitute.dylib' $$@ tests: out/test-$(1) endef $(eval $(call define_test,tdarm-simple,td-simple,$(CC) -std=c11 -DHDR='"arm/dis-arm.inc.h"' -Dxdis=dis_arm -DFORCE_TARGET_arm)) @@ -132,6 +132,7 @@ $(eval $(call define_test,inject,inject,$(CC) -std=c11 -lsubstitute out/darwin/i $(eval $(call define_test,stop-threads,stop-threads,$(CC) -std=c11 out/darwin/stop-other-threads.o -framework CoreFoundation)) $(eval $(call define_test,execmem,execmem,$(CC) -std=c11 out/darwin/execmem.o -segprot __TEST rwx rx)) $(eval $(call define_test,hook-functions,hook-functions,$(CC) -std=c11 -lsubstitute)) +$(eval $(call define_test,posixspawn-hook,posixspawn-hook,$(CC) -std=c11)) out/injected-test-dylib.dylib: test/injected-test-dylib.c Makefile $(CC) -std=c11 -dynamiclib -o $@ $< diff --git a/ios-bootstrap/posixspawn-hook.c b/ios-bootstrap/posixspawn-hook.c index 1f1bae1..525b597 100644 --- a/ios-bootstrap/posixspawn-hook.c +++ b/ios-bootstrap/posixspawn-hook.c @@ -6,6 +6,7 @@ #include <sys/wait.h> #include <syslog.h> #include <malloc/malloc.h> +#include <assert.h> extern char ***_NSGetEnviron(void); @@ -66,6 +67,7 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old, const char *p = orig_dyld_insert; while (*p) { /* W.N.H. */ const char *next = strchr(p, ':') ?: (p + strlen(p)); + printf("p:%s next:%s\n", p, next); /* append if it isn't a copy of ours */ if (!(next - p == sizeof(my_dylib) - 1 && memcmp(next, my_dylib, sizeof(my_dylib) - 1))) { @@ -74,7 +76,9 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old, memcpy(newp, p, next - p); newp += next - p; } + p = next; } + printf("ok\n"); /* append ours if necessary */ if (!safe_mode) { if (newp != newp_orig) @@ -90,7 +94,7 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old, envp_to_use = new_envp; char **outp = new_envp; for (size_t idx = 0; idx < env_count; idx++) { - char *env = envp[idx]; + char *env = my_envp[idx]; /* remove *all* D_I_L, including duplicates */ if (!advance(&env, "DYLD_INSERT_LIBRARIES=")) *outp++ = env; @@ -141,10 +145,13 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old, goto cleanup; /* Since it returned, obviously it was not SETEXEC, so we need to * unrestrict ourself. */ - int sret = substitute_ios_unrestrict(*pid, !was_suspended); + char *error; + int sret = substitute_ios_unrestrict(*pid, !was_suspended, &error); if (sret) { - syslog(LOG_EMERG, "posixspawn-hook: substitute_ios_unrestrict => %d", sret); + syslog(LOG_EMERG, "posixspawn-hook: substitute_ios_unrestrict => %d (%s)", + sret, error); } + free(error); goto cleanup; crap: syslog(LOG_EMERG, "posixspawn-hook: weird error - OOM? skipping our stuff"); @@ -239,3 +246,17 @@ end: if (mach_msg_send(&done_hdr)) /* MOVE deallocates port */ syslog(LOG_EMERG, "posixspawn-hook: mach_msg_send failed"); } + +__attribute__((constructor)) +static void init() { + if (getenv("TEST_POSIXSPAWN_HOOK")) { + mach_port_t port; + assert(!mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_DEAD_NAME, + &port)); + struct shuttle shuttle = { + .type = SUBSTITUTE_SHUTTLE_MACH_PORT, + .u.mach.port = port + }; + substitute_init(&shuttle, 1); + } +} diff --git a/ios-bootstrap/unrestrict-me.c b/ios-bootstrap/unrestrict-me.c index 718e9f8..a297471 100644 --- a/ios-bootstrap/unrestrict-me.c +++ b/ios-bootstrap/unrestrict-me.c @@ -22,9 +22,11 @@ int main(int argc, char **argv) { return 1; } - int sret = substitute_ios_unrestrict((pid_t) pid, should_resume[0] == '1'); + char *err = NULL; + int sret = substitute_ios_unrestrict((pid_t) pid, should_resume[0] == '1', &err); if (sret) { - syslog(LOG_EMERG, "unrestrict-me: substitute_ios_unrestrict => %d", sret); + syslog(LOG_EMERG, "unrestrict-me: substitute_ios_unrestrict => %d (%s)", + sret, err); return 1; } diff --git a/lib/darwin/unrestrict.c b/lib/darwin/unrestrict.c index 4fd90da..6526019 100644 --- a/lib/darwin/unrestrict.c +++ b/lib/darwin/unrestrict.c @@ -4,7 +4,8 @@ #include <unistd.h> #include <mach/vm_region.h> -static int unrestrict_macho_header(void *header, size_t size, bool *did_modify_p) { +static int unrestrict_macho_header(void *header, size_t size, bool *did_modify_p, + char **error) { *did_modify_p = false; struct mach_header *mh = header; if (mh->magic != MH_MAGIC && mh->magic != MH_MAGIC_64) @@ -30,8 +31,10 @@ static int unrestrict_macho_header(void *header, size_t size, bool *did_modify_p CASES( segment_command_y *sc = (void *) lc; if (lc->cmdsize < sizeof(*sc) || - sc->nsects > (lc->cmdsize - sizeof(*sc)) / sizeof(struct section)) + sc->nsects > (lc->cmdsize - sizeof(*sc)) / sizeof(struct section)) { + asprintf(error, "bad segment_command"); return SUBSTITUTE_ERR_MISC; + } if (!strncmp(sc->segname, "__RESTRICT", 16)) { section_y *sect = (void *) (sc + 1); for (uint32_t i = 0; i < sc->nsects; i++, sect++) { @@ -44,15 +47,18 @@ static int unrestrict_macho_header(void *header, size_t size, bool *did_modify_p ) #undef CASES - if (off + lc->cmdsize < off) + if (off + lc->cmdsize < off) { + asprintf(error, "overflowing lc->cmdsize"); return SUBSTITUTE_ERR_MISC; + } off += lc->cmdsize; } return SUBSTITUTE_OK; } EXPORT -int substitute_ios_unrestrict(pid_t pid, bool should_resume) { +int substitute_ios_unrestrict(pid_t pid, bool should_resume, char **error) { + *error = NULL; mach_port_t task; kern_return_t kr = task_for_pid(mach_task_self(), pid, &task); if (kr) @@ -72,12 +78,16 @@ setback: kern_return_t kr = task_info(task, TASK_DYLD_INFO, (void *) &tdi, &cnt); if (kr || cnt != TASK_DYLD_INFO_COUNT) { + asprintf(error, "task_info: %x", kr); ret = SUBSTITUTE_ERR_MISC; goto fail; } + printf("=>%llx\n", tdi.all_image_info_addr); + printf("=>%llx\n", tdi.all_image_info_size); if (tdi.all_image_info_size == 0) break; if (retries++ == 20) { + asprintf(error, "all_image_info_size was not 0 after 20 retries"); ret = SUBSTITUTE_ERR_MISC; goto fail; } @@ -102,6 +112,7 @@ setback: /* nothing! maybe it's not there *yet*? this actually is possible */ goto setback; } else if (kr) { + asprintf(error, "mach_vm_region(%lx): %x", (long) segm_addr, kr); ret = SUBSTITUTE_ERR_VM; goto fail; } @@ -116,6 +127,7 @@ setback: toread = segm_size; if ((kr = vm_allocate(mach_task_self(), &header_addr, toread, VM_FLAGS_ANYWHERE))) { + asprintf(error, "vm_allocate(%zx): %x", toread, kr); ret = SUBSTITUTE_ERR_MISC; goto fail; } @@ -123,18 +135,21 @@ setback: kr = mach_vm_read_overwrite(task, segm_addr, toread, header_addr, &actual); if (kr || actual != toread) { + asprintf(error, "mach_vm_read_overwrite: %x", kr); ret = SUBSTITUTE_ERR_MISC; goto fail; } bool did_modify; if ((ret = unrestrict_macho_header((void *) header_addr, toread, - &did_modify))) + &did_modify, error))) goto fail; if (did_modify) { if ((kr = vm_protect(mach_task_self(), header_addr, toread, FALSE, info.protection))) { + asprintf(error, "vm_protect(%lx=>%d): %x", + (long) header_addr, info.protection, kr); ret = SUBSTITUTE_ERR_VM; goto fail; } @@ -142,7 +157,9 @@ setback: if ((kr = mach_vm_remap(task, &segm_addr, toread, 0, VM_FLAGS_OVERWRITE, mach_task_self(), header_addr, FALSE, - &cur, &max, info.inheritance))) { + &cur, &max, info.inheritance))) { + asprintf(error, "mach_vm_remap(%lx=>%lx * %zx): %x", + (long) header_addr, (long) segm_addr, toread, kr); ret = SUBSTITUTE_ERR_VM; goto fail; } @@ -151,8 +168,10 @@ setback: ret = SUBSTITUTE_OK; fail: if (should_resume) { - if ((kr = task_resume(task))) + if ((kr = task_resume(task))) { + asprintf(error, "task_resume: %x", kr); ret = SUBSTITUTE_ERR_MISC; + } } mach_port_deallocate(mach_task_self(), task); if (header_addr) diff --git a/lib/substitute-internal.h b/lib/substitute-internal.h index b378989..e240020 100644 --- a/lib/substitute-internal.h +++ b/lib/substitute-internal.h @@ -86,5 +86,5 @@ int substitute_dlopen_in_pid(int pid, const char *filename, int options, const struct shuttle *shuttle, size_t nshuttle, char **error); -int substitute_ios_unrestrict(pid_t pid, bool should_resume); +int substitute_ios_unrestrict(pid_t pid, bool should_resume, char **error); #endif diff --git a/test/test-posixspawn-hook.c b/test/test-posixspawn-hook.c new file mode 100644 index 0000000..409f5fe --- /dev/null +++ b/test/test-posixspawn-hook.c @@ -0,0 +1,9 @@ +#include <spawn.h> +#include <stdlib.h> +#include <stdio.h> +int main(__attribute__((unused)) int argc, char **argv) { + pid_t pid = 0; + printf("doing it:\n"); + int ret = posix_spawn(&pid, argv[1], NULL, NULL, argv + 1, NULL); + printf("==> %d pid=%d\n", ret, pid); +} |