aboutsummaryrefslogtreecommitdiff
path: root/ios-bootstrap/posixspawn-hook.c
diff options
context:
space:
mode:
authorcomex2015-01-29 21:31:11 -0500
committercomex2015-01-29 21:31:11 -0500
commit6fecd889e388f7642969d58bfe429a756d29413f (patch)
treef5f28651b14e46294df34040428303f156163f29 /ios-bootstrap/posixspawn-hook.c
parent"Fix" broken launchd injection stuff. (diff)
downloadsubstitute-6fecd889e388f7642969d58bfe429a756d29413f.tar.gz
a bunch of stuff that should have been committed separately
Diffstat (limited to 'ios-bootstrap/posixspawn-hook.c')
-rw-r--r--ios-bootstrap/posixspawn-hook.c119
1 files changed, 64 insertions, 55 deletions
diff --git a/ios-bootstrap/posixspawn-hook.c b/ios-bootstrap/posixspawn-hook.c
index 9ea9621..f1aff4e 100644
--- a/ios-bootstrap/posixspawn-hook.c
+++ b/ios-bootstrap/posixspawn-hook.c
@@ -8,6 +8,7 @@
#include <malloc/malloc.h>
#include <assert.h>
#include <dispatch/dispatch.h>
+#include <errno.h>
extern char ***_NSGetEnviron(void);
@@ -28,6 +29,7 @@ static void open_logfp_if_necessary() {
}
#define psh_log(fmt, args...) do { \
open_logfp_if_necessary(); \
+ syslog(LOG_EMERG, fmt, ##args); \
fprintf(logfp, fmt "\n", ##args); \
fflush(logfp); \
} while(0)
@@ -46,7 +48,7 @@ static bool advance(char **strp, const char *template) {
return false;
}
-static bool spawn_unrestrict_me(pid_t pid, bool should_resume) {
+static bool spawn_unrestrict(pid_t pid, bool should_resume) {
const char *prog = "/Library/Substitute/unrestrict";
char pid_s[32];
sprintf(pid_s, "%ld", (long) pid);
@@ -59,8 +61,9 @@ static bool spawn_unrestrict_me(pid_t pid, bool should_resume) {
}
int xstat;
/* reap intermediate to avoid zombie - if it doesn't work, not a big deal */
- if (waitpid(prog_pid, &xstat, 0))
+ if (waitpid(prog_pid, &xstat, 0) == -1)
psh_log("posixspawn-hook: couldn't waitpid");
+ psh_log("unrestrict xstat=%x", xstat);
return true;
}
@@ -75,6 +78,29 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old,
char *const *envp_to_use = envp;
char *const *my_envp = envp ? envp : *_NSGetEnviron();
posix_spawnattr_t my_attr = NULL;
+
+ if (attrp) {
+ posix_spawnattr_t attr = *attrp;
+ size_t size = malloc_size(attr);
+ my_attr = malloc(size);
+ if (!my_attr)
+ goto crap;
+ memcpy(my_attr, attr, size);
+ } else {
+ if (posix_spawnattr_init(&my_attr))
+ goto crap;
+ }
+
+ short flags;
+ if (posix_spawnattr_getflags(&my_attr, &flags))
+ goto crap;
+ psh_log("hook_posix_spawn_generic: path=%s%s%s",
+ path,
+ (flags & POSIX_SPAWN_SETEXEC) ? " (exec)" : "",
+ (flags & POSIX_SPAWN_START_SUSPENDED) ? " (suspend)" : "");
+ for (char *const *ap = argv; *ap; ap++)
+ psh_log(" %s", *ap);
+
/* This mirrors Substrate's logic with safe mode. I don't really
* understand the point of the difference between its 'safe' (which removes
* Substrate from DYLD_INSERT_LIBRARIES) and 'quit' (which just skips
@@ -129,11 +155,12 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old,
if (!safe_mode) {
if (newp != newp_orig)
*newp++ = ':';
- const char *dylib_to_add = !strncmp(path, "/usr/libexec/xpcproxy"))
+ const char *dylib_to_add = !strcmp(path, "/usr/libexec/xpcproxy")
? my_dylib_2
: my_dylib_1;
newp = stpcpy(newp, dylib_to_add);
}
+ psh_log("using %s", new);
/* no libraries? then just get rid of it */
if (newp == newp_orig) {
free(new);
@@ -157,34 +184,26 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old,
/* Deal with the dumb __restrict section. A complication is that this
* could actually be an exec. */
- if (attrp) {
- posix_spawnattr_t attr = *attrp;
- size_t size = malloc_size(attr);
- my_attr = malloc(size);
- if (!my_attr)
- goto crap;
- memcpy(my_attr, attr, size);
- } else {
- if (posix_spawnattr_init(&my_attr))
- goto crap;
- }
- short flags;
- if (posix_spawnattr_getflags(&my_attr, &flags))
- goto crap;
+ /* TODO skip this if Substrate is doing it anyway */
bool was_suspended = flags & POSIX_SPAWN_START_SUSPENDED;
flags |= POSIX_SPAWN_START_SUSPENDED;
if (posix_spawnattr_setflags(&my_attr, flags))
goto crap;
if (flags & POSIX_SPAWN_SETEXEC) {
- if (!spawn_unrestrict_me(getpid(), !was_suspended))
+ /* make the marker fd; hope you weren't using that */
+ if (dup2(2, 255) != 255) {
+ psh_log("dup2 failure - %s", strerror(errno));
+ goto skip;
+ }
+ if (fcntl(255, F_SETFD, FD_CLOEXEC))
+ goto crap;
+ psh_log("spawning unrestrict");
+ if (!spawn_unrestrict(getpid(), !was_suspended))
goto skip;
}
-
- psh_log("calling old <path=%s>", path);
- for (char *const *ap = argv; *ap; ap++)
- psh_log(" %s", *ap);
+ psh_log("**");
int ret = old(pidp, path, file_actions, &my_attr, argv, envp_to_use);
- psh_log("ret=%d", ret);
+ psh_log("ret=%d pid=%ld", ret, (long) *pidp);
if (ret)
goto cleanup;
/* Since it returned, obviously it was not SETEXEC, so we need to
@@ -212,7 +231,7 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old,
free(error);
});
#else
- spawn_unrestrict_me(pid, !was_suspended);
+ spawn_unrestrict(pid, !was_suspended);
#endif
goto cleanup;
crap:
@@ -227,9 +246,9 @@ cleanup:
}
static void after_wait_generic(pid_t pid, int stat) {
+ /* TODO safety */
(void) pid;
(void) stat;
-
}
int hook_posix_spawn(pid_t *restrict pid, const char *restrict path,
@@ -260,12 +279,28 @@ pid_t hook_waitpid(pid_t pid, int *stat_loc, int options) {
return ret;
}
-void substitute_init(struct shuttle *shuttle, UNUSED size_t nshuttle) {
- /* Don't hook twice - that will just mess things up. */
- static int already_initted;
- if (__atomic_exchange_n(&already_initted, 1, __ATOMIC_RELAXED))
+void substitute_init(struct shuttle *shuttle, size_t nshuttle) {
+ /* Just tell them we're done */
+ if (nshuttle != 1) {
+ psh_log("nshuttle = %zd?", nshuttle);
return;
+ }
+ mach_port_t notify_port = shuttle[0].u.mach.port;
+ mach_msg_header_t done_hdr;
+ done_hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND, 0);
+ done_hdr.msgh_size = sizeof(done_hdr);
+ done_hdr.msgh_remote_port = notify_port;
+ done_hdr.msgh_local_port = 0;
+ done_hdr.msgh_voucher_port = 0;
+ done_hdr.msgh_id = 42;
+ kern_return_t kr = mach_msg_send(&done_hdr);
+ if (kr)
+ psh_log("posixspawn-hook: mach_msg_send failed: kr=%x", kr);
+ /* MOVE deallocated the port */
+}
+__attribute__((constructor))
+static void init() {
/* Note: I'm using interposing to minimize the chance of conflict with
* Substrate. This shouldn't actually be necessary, because MSHookProcess,
* at least as of the old version I'm looking at the source code of, blocks
@@ -305,30 +340,4 @@ end:
if (im)
substitute_close_image(im);
- mach_port_t notify_port = shuttle[0].u.mach.port;
- mach_msg_header_t done_hdr;
- done_hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
- done_hdr.msgh_size = sizeof(done_hdr);
- done_hdr.msgh_remote_port = notify_port;
- done_hdr.msgh_local_port = 0;
- done_hdr.msgh_voucher_port = 0;
- done_hdr.msgh_id = 42;
- kern_return_t kr = mach_msg_send(&done_hdr);
- if (kr)
- psh_log("posixspawn-hook: mach_msg_send failed: kr=%x", kr);
- /* MOVE deallocated the port */
-}
-
-__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);
- }
}