aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--ios-bootstrap/posixspawn-hook.c27
-rw-r--r--ios-bootstrap/unrestrict-me.c6
-rw-r--r--lib/darwin/unrestrict.c33
-rw-r--r--lib/substitute-internal.h2
-rw-r--r--test/test-posixspawn-hook.c9
6 files changed, 66 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index 4499d15..9fd0c34 100644
--- a/Makefile
+++ b/Makefile
@@ -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);
+}