diff options
author | comex | 2015-07-11 17:57:30 -0400 |
---|---|---|
committer | comex | 2015-07-11 17:57:34 -0400 |
commit | 8f10eb58e5014e7e0326d7455f3999bf62d14a9b (patch) | |
tree | 2ff0b6a937aa6846fd403e81210c523be10208e5 /darwin-bootstrap | |
parent | fix anti-noise (diff) | |
download | substitute-8f10eb58e5014e7e0326d7455f3999bf62d14a9b.tar.gz |
working on safety
Diffstat (limited to 'darwin-bootstrap')
-rw-r--r-- | darwin-bootstrap/bundle-loader.c | 22 | ||||
-rw-r--r-- | darwin-bootstrap/posixspawn-hook.c | 31 | ||||
-rw-r--r-- | darwin-bootstrap/substituted.m | 134 |
3 files changed, 111 insertions, 76 deletions
diff --git a/darwin-bootstrap/bundle-loader.c b/darwin-bootstrap/bundle-loader.c index 49e6152..ed4dde4 100644 --- a/darwin-bootstrap/bundle-loader.c +++ b/darwin-bootstrap/bundle-loader.c @@ -27,6 +27,8 @@ static struct { typeof(objc_getClass) *objc_getClass; } objc_funcs; +static xxpc_connection_t substituted_conn; + static pthread_mutex_t hello_reply_mtx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t hello_reply_cond = PTHREAD_COND_INITIALIZER; static xxpc_object_t hello_reply; @@ -191,6 +193,13 @@ static void handle_xxpc_object(xxpc_object_t object, bool is_reply) { free(desc); } +static void inform_sud_of_clean_exit() { + xxpc_object_t message = xxpc_dictionary_create(NULL, NULL, 0); + xxpc_dictionary_set_string(message, "type", "bye"); + xxpc_connection_send_message(substituted_conn, message); + xxpc_release(message); +} + /* this is DYLD_INSERT_LIBRARIES'd, not injected. */ __attribute__((constructor)) static void init() { @@ -199,11 +208,10 @@ static void init() { /* it's not supposed to return null, but just in case */ if (!conn) { ib_log("xxpc_connection_create_mach_service returned null"); - return; + goto bad; } - __block xxpc_object_t received_dict = NULL; - __block bool did_receive_dict = false; + substituted_conn = conn; xxpc_connection_set_event_handler(conn, ^(xxpc_object_t object) { handle_xxpc_object(object, false); @@ -259,14 +267,14 @@ static void init() { char *desc = xxpc_copy_description(hello_reply); ib_log("received invalid message from substituted: %s", desc); free(desc); + xxpc_release(hello_reply); goto bad; } + xxpc_release(hello_reply); + + atexit(inform_sud_of_clean_exit); return; bad: - if (hello_reply) { - xxpc_release(hello_reply); - hello_reply = NULL; - } ib_log("giving up on loading bundles for this process..."); } diff --git a/darwin-bootstrap/posixspawn-hook.c b/darwin-bootstrap/posixspawn-hook.c index 4920d0a..3c37403 100644 --- a/darwin-bootstrap/posixspawn-hook.c +++ b/darwin-bootstrap/posixspawn-hook.c @@ -36,8 +36,6 @@ extern char ***_NSGetEnviron(void); static __typeof__(posix_spawn) *old_posix_spawn, *old_posix_spawnp, hook_posix_spawn, hook_posix_spawnp; -static __typeof__(wait4) *old_wait4, hook_wait4; -static typeof(waitpid) *old_waitpid, hook_waitpid; static int (*old_sandbox_check)(pid_t, const char *, int type, ...); static bool is_launchd; @@ -187,10 +185,9 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old, /* which dylib should we add, if any? */ const char *dylib_to_add; if (is_launchd) { - if (!strcmp(path, "/usr/libexec/xpcproxy")) - dylib_to_add = psh_dylib; - else + if (strcmp(path, "/usr/libexec/xpcproxy")) goto skip; + dylib_to_add = psh_dylib; } else { /* - substituted obviously doesn't want to have bundle_loader run in it * and try to contact substituted. I have _MSSafeMode=1 in the plist @@ -220,8 +217,7 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old, !strcmp(path, "/usr/sbin/notifyd") || !strcmp(xbasename(argv[0] ?: ""), "sshd")) goto skip; - else - dylib_to_add = bl_dylib; + dylib_to_add = bl_dylib; } if (access(dylib_to_add, R_OK)) { @@ -347,6 +343,7 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old, int ret = old(pidp, path, file_actions, &my_attr, argv, envp_to_use); if (IB_VERBOSE) ib_log("ret=%d pid=%ld", ret, (long) *pidp); + if (ret) goto cleanup; /* Since it returned, obviously it was not SETEXEC, so we need to @@ -366,12 +363,6 @@ cleanup: return ret; } -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, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *restrict attrp, @@ -388,18 +379,6 @@ int hook_posix_spawnp(pid_t *restrict pid, const char *restrict path, attrp, argv, envp); } -pid_t hook_wait4(pid_t pid, int *stat_loc, int options, struct rusage *rusage) { - pid_t ret = old_wait4(pid, stat_loc, options, rusage); - after_wait_generic(ret, *stat_loc); - return ret; -} - -pid_t hook_waitpid(pid_t pid, int *stat_loc, int options) { - pid_t ret = old_waitpid(pid, stat_loc, options); - after_wait_generic(ret, *stat_loc); - return ret; -} - int hook_sandbox_check(pid_t pid, const char *op, int type, ...) { /* Can't easily determine the number of arguments, so just assume there's * less than 5 pointers' worth. */ @@ -468,8 +447,6 @@ static void init() { static const struct substitute_import_hook hooks[] = { {"_posix_spawn", hook_posix_spawn, &old_posix_spawn}, {"_posix_spawnp", hook_posix_spawnp, &old_posix_spawnp}, - {"_waitpid", hook_waitpid, &old_waitpid}, - {"_wait4", hook_wait4, &old_wait4}, {"_sandbox_check", hook_sandbox_check, &old_sandbox_check}, }; diff --git a/darwin-bootstrap/substituted.m b/darwin-bootstrap/substituted.m index ca793ba..5cb1b11 100644 --- a/darwin-bootstrap/substituted.m +++ b/darwin-bootstrap/substituted.m @@ -9,6 +9,8 @@ * libraries into the target binary (unless actually required by loaded * libraries). In the future it will help with hot loading. */ +static bool g_springboard_needs_safe; + extern kern_return_t bootstrap_look_up3(mach_port_t bp, const char *service_name, mach_port_t *sp, pid_t target_pid, const uuid_t instance_id, uint64_t flags); @@ -32,12 +34,6 @@ static void install_deadlock_warning() { } } -enum convert_filters_ret { - PROVISIONAL_PASS, - FAIL, - INVALID -}; - static double id_to_double(id o) { if ([o isKindOfClass:[NSString class]]) { NSScanner *scan = [NSScanner scannerWithString:o]; @@ -56,10 +52,27 @@ static xxpc_object_t nsstring_to_xpc(NSString *in) { return xxpc_string_create([in cStringUsingEncoding:NSUTF8StringEncoding]); } -static enum convert_filters_ret convert_filters(NSDictionary *plist_dict, - const char *exec_name, - xxpc_object_t out_info) { +@interface PeerHandler : NSObject { + xxpc_object_t _connection; + NSString *_argv0; + bool _is_springboard, _got_bye; +} + +@end + +enum convert_filters_ret TEST; +@implementation PeerHandler + +enum convert_filters_ret { + PROVISIONAL_PASS, + FAIL, + INVALID +}; + +- (enum convert_filters_ret) + convertFiltersForBundleInfo:(NSDictionary *)plist_dict + toXPCReply:(xxpc_object_t)out_info { NSDictionary *filter = [plist_dict objectForKey:@"Filter"]; if (!filter) return PROVISIONAL_PASS; @@ -72,11 +85,24 @@ static enum convert_filters_ret convert_filters(NSDictionary *plist_dict, [key isEqualToString:@"Classes"] || [key isEqualToString:@"Bundles"] || [key isEqualToString:@"Executables"] || - [key isEqualToString:@"Mode"])) { + [key isEqualToString:@"Mode"] || + [key isEqualToString:@"SafeMode"])) { return INVALID; } } + bool safe_mode = false; + NSNumber *safe_mode_num = [filter objectForKey:@"SafeMode"]; + if (safe_mode_num) { + if ([safe_mode_num isEqual:[NSNumber numberWithBool:true]]) + safe_mode = true; + else if (![safe_mode_num isEqual:[NSNumber numberWithBool:false]]) + return INVALID; + } + if ((safe_mode && !_is_springboard) || + safe_mode != g_springboard_needs_safe) + return FAIL; + bool any = false; NSString *mode_str = [filter objectForKey:@"Mode"]; if (mode_str) { @@ -113,18 +139,16 @@ static enum convert_filters_ret convert_filters(NSDictionary *plist_dict, NSArray *executables = [filter objectForKey:@"Executables"]; if (executables) { - NSString *exe = [NSString stringWithCString:exec_name - encoding:NSUTF8StringEncoding]; if (![executables isKindOfClass:[NSArray class]]) return INVALID; for (NSString *name in executables) { if (![name isKindOfClass:[NSString class]]) return INVALID; - if ([name isEqualToString:exe]) + if ([name isEqualToString:_argv0]) goto ok; } if (any) - return PROVISIONAL_PASS; // without adding other conditions + return PROVISIONAL_PASS; /* without adding other conditions */ else return FAIL; ok:; @@ -152,15 +176,24 @@ static enum convert_filters_ret convert_filters(NSDictionary *plist_dict, xxpc_array_append_value(out_things, nsstring_to_xpc(name)); } xxpc_dictionary_set_value(out_info, types[i].okey, out_things); - xxpc_release(out_things); } } return PROVISIONAL_PASS; } -xxpc_object_t get_hello_bundles(const char *exec_name) { - /* TODO cache */ +- (bool)handleMessageHello:(xxpc_object_t)request { + if (_argv0 != NULL) + return false; + + const char *argv0 = xxpc_dictionary_get_string(request, "argv0"); + if (!argv0) + return false; + _argv0 = [NSString stringWithCString:argv0 + encoding:NSUTF8StringEncoding]; + + _is_springboard = [_argv0 isEqualToString:@"SpringBoard"]; + xxpc_object_t bundles = xxpc_array_create(NULL, 0); NSError *err; @@ -187,7 +220,8 @@ xxpc_object_t get_hello_bundles(const char *exec_name) { xxpc_object_t info = xxpc_dictionary_create(NULL, NULL, 0); - enum convert_filters_ret ret = convert_filters(plist_dict, exec_name, info); + enum convert_filters_ret ret = + [self convertFiltersForBundleInfo:plist_dict toXPCReply:info]; if (ret == FAIL) { continue; } else if (ret == INVALID) { @@ -199,47 +233,63 @@ xxpc_object_t get_hello_bundles(const char *exec_name) { xxpc_dictionary_set_value(info, "dylib", nsstring_to_xpc(dylib_path)); xxpc_array_append_value(bundles, info); - xxpc_release(info); } - return bundles; + xxpc_object_t reply = xxpc_dictionary_create_reply(request); + xxpc_dictionary_set_value(reply, "bundles", bundles); + xxpc_connection_send_message(_connection, reply); + return true; +} + +- (bool)handleMessageBye:(xxpc_object_t)request { + _got_bye = true; + return true; +} + +- (void)handleHangup { + /* this could be false because hello hasn't been sent, but in that case it + * hasn't loaded any substitute dylibs, so not our problem *whistle* */ + if (_is_springboard && !_got_bye) { + NSLog(@"SpringBoard hung up without saying bye; using safe mode next time."); + g_springboard_needs_safe = true; + } } -#define PRECISE objc_precise_lifetime -static bool handle_message(xxpc_object_t request, xxpc_object_t reply) { +- (bool)handleMessage:(xxpc_object_t)request { const char *type = xxpc_dictionary_get_string(request, "type"); - if (!type || strcmp(type, "hello")) + if (!type) return false; - const char *argv0 = xxpc_dictionary_get_string(request, "argv0"); - if (!argv0) + if (!strcmp(type, "hello")) + return [self handleMessageHello:request]; + else if (!strcmp(type, "bye")) + return [self handleMessageBye:request]; + else return false; - xxpc_object_t bundles = get_hello_bundles(argv0); - xxpc_dictionary_set_value(reply, "bundles", bundles); - xxpc_release(bundles); - return true; } -static void init_peer(xxpc_object_t peer) { - xxpc_connection_set_event_handler(peer, ^(xxpc_object_t event) { +- (instancetype)initWithConnection:(xxpc_object_t)connection { + _connection = connection; + xxpc_connection_set_event_handler(connection, ^(xxpc_object_t event) { xxpc_type_t ty = xxpc_get_type(event); if (ty == XXPC_TYPE_DICTIONARY) { - xxpc_object_t reply = xxpc_dictionary_create_reply(event); - if (handle_message(event, reply)) - xxpc_connection_send_message(peer, reply); - else - xxpc_connection_cancel(peer); - xxpc_release(reply); + if (![self handleMessage:event]) + xxpc_connection_cancel(connection); } else if (ty == XXPC_TYPE_ERROR) { - if (event == XXPC_ERROR_CONNECTION_INVALID) - return; - NSLog(@"XPC error from peer: %@", event); + if (event == XXPC_ERROR_CONNECTION_INVALID) { + [self handleHangup]; + } else { + NSLog(@"XPC error from connection: %@", event); + xxpc_connection_cancel(connection); + } } else { NSLog(@"unknown object received from XPC (peer): %@", event); } }); - xxpc_connection_resume(peer); + xxpc_connection_resume(connection); + return self; } +@end int main() { NSLog(@"hello from substituted"); @@ -253,7 +303,7 @@ int main() { xxpc_connection_set_event_handler(listener, ^(xxpc_object_t object) { xxpc_type_t ty = xxpc_get_type(object); if (ty == XXPC_TYPE_CONNECTION) { - init_peer(object); + (void) [[PeerHandler alloc] initWithConnection:object]; } else if (ty == XXPC_TYPE_ERROR) { NSLog(@"XPC error in server: %@", object); exit(1); |