diff options
author | comex | 2015-07-07 18:50:18 -0400 |
---|---|---|
committer | comex | 2015-07-07 18:54:34 -0400 |
commit | 2b6d33a8490c56612f207ecd51d0e2e272220642 (patch) | |
tree | 266c76fd4f073952fc4ca42553edc27836319411 /darwin-bootstrap/substituted.m | |
parent | Merge branch 'mconfig-work' (diff) | |
download | substitute-2b6d33a8490c56612f207ecd51d0e2e272220642.tar.gz |
redo all the things with xpc - not tested yet
Diffstat (limited to '')
-rw-r--r-- | darwin-bootstrap/substituted.m (renamed from darwin-bootstrap/substituted-plist-loader.m) | 153 |
1 files changed, 110 insertions, 43 deletions
diff --git a/darwin-bootstrap/substituted-plist-loader.m b/darwin-bootstrap/substituted.m index 0c8d66f..cfa1541 100644 --- a/darwin-bootstrap/substituted-plist-loader.m +++ b/darwin-bootstrap/substituted.m @@ -1,6 +1,6 @@ #import <Foundation/Foundation.h> #import <CoreFoundation/CoreFoundation.h> -#include "substituted-messages.h" +#include "xxpc.h" enum convert_filters_ret { PROVISIONAL_PASS, @@ -22,13 +22,18 @@ static double id_to_double(id o) { } } +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, - NSMutableData *test_out) { + xxpc_object_t out_info) { NSDictionary *filter = [plist_dict objectForKey:@"Filter"]; if (!filter) return PROVISIONAL_PASS; + if (![filter isKindOfClass:[NSDictionary class]]) return INVALID; @@ -36,11 +41,22 @@ static enum convert_filters_ret convert_filters(NSDictionary *plist_dict, if (!([key isEqualToString:@"CoreFoundationVersion"] || [key isEqualToString:@"Classes"] || [key isEqualToString:@"Bundles"] || - [key isEqualToString:@"Executables"])) { + [key isEqualToString:@"Executables"] || + [key isEqualToString:@"Mode"])) { return INVALID; } } + bool any = false; + NSString *mode_str = [filter objectForKey:@"Mode"]; + if (mode_str) { + any = [mode_str isEqual:@"Any"]; + if (!any && ![mode_str isEqual:@"All"]) + return INVALID; + } + + xxpc_dictionary_set_bool(out_info, "any", any); + /* First do the two we can test here. */ NSArray *cfv = [filter objectForKey:@"CoreFoundationVersion"]; @@ -77,59 +93,53 @@ static enum convert_filters_ret convert_filters(NSDictionary *plist_dict, if ([name isEqualToString:exe]) goto ok; } - return FAIL; + if (any) + return PROVISIONAL_PASS; // without adding other conditions + else + return FAIL; ok:; } - /* Convert the rest to substituted_bundle_list_ops. */ + /* Convert the rest to tests for bundle-loader. */ struct { __unsafe_unretained NSString *key; - uint8_t opc; + const char *okey; } types[2] = { - {@"Classes", SUBSTITUTED_TEST_CLASS}, - {@"Bundles", SUBSTITUTED_TEST_BUNDLE}, + {@"Classes", "classes"}, + {@"Bundles", "bundles"}, }; for (int i = 0; i < 2; i++) { NSArray *things = [filter objectForKey:types[i].key]; if (things) { + xxpc_object_t out_things = xxpc_array_create(NULL, 0); if (![things isKindOfClass:[NSArray class]]) return INVALID; for (NSString *name in things) { if (![name isKindOfClass:[NSString class]]) return INVALID; - NSData *name_data = [name dataUsingEncoding:NSUTF8StringEncoding]; - size_t len = [name_data length]; - if (len > 65535) - return INVALID; - struct substituted_bundle_list_op op = {(uint16_t) len, - types[i].opc}; - [test_out appendBytes:&op length:sizeof(op)]; - [test_out appendData:name_data]; - static char zero = '\0'; - [test_out appendBytes:&zero length:1]; + 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; } -static NSData *the_bundle_list; - -void get_bundle_list(const char *exec_name, - const void **bundle_list, size_t *bundle_list_size) { +xxpc_object_t get_hello_bundles(const char *exec_name) { /* TODO cache */ + xxpc_object_t bundles = xxpc_array_create(NULL, 0); + NSError *err; NSString *base = @"/Library/Substitute/DynamicLibraries"; NSArray *list = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:base error:&err]; if (!list) - return; - - NSMutableData *out = [NSMutableData data]; + return bundles; for (NSString *dylib in list) { if (![[dylib pathExtension] isEqualToString:@"dylib"]) @@ -140,34 +150,91 @@ void get_bundle_list(const char *exec_name, NSDictionary *plist_dict = [NSDictionary dictionaryWithContentsOfFile: full_plist]; if (!plist_dict) { - NSLog(@"missing, unreadable, or invalid plist '%@' for dylib '%@'; unlike Substrate, we require plists", full_plist, dylib); + NSLog(@"missing, unreadable, or invalid plist '%@' for dylib '%@'; unlike Substrate, we require plists", + full_plist, dylib); continue; } - NSMutableData *test = [NSMutableData data]; - enum convert_filters_ret ret = convert_filters(plist_dict, exec_name, test); + xxpc_object_t info = xxpc_dictionary_create(NULL, NULL, 0); + + enum convert_filters_ret ret = convert_filters(plist_dict, exec_name, info); if (ret == FAIL) { continue; } else if (ret == INVALID) { NSLog(@"bad data in plist '%@' for dylib '%@'", full_plist, dylib); continue; } + NSString *dylib_path = [base stringByAppendingPathComponent:dylib]; - NSData *dylib_path_data = [dylib_path dataUsingEncoding:NSUTF8StringEncoding]; - size_t len = [dylib_path length]; - if (len > 65535) { - NSLog(@"dylib '%@' somehow has an absurdly long path", dylib); - continue; + xxpc_dictionary_set_value(info, "dylib", nsstring_to_xpc(dylib_path)); + + xxpc_array_append_value(bundles, info); + xxpc_release(info); + } + + return bundles; +} + +#define PRECISE objc_precise_lifetime + +static bool handle_message(xxpc_object_t request, xxpc_object_t reply) { + const char *type = xxpc_dictionary_get_string(request, "type"); + if (!type || strcmp(type, "hello")) + return false; + const char *argv0 = xxpc_dictionary_get_string(request, "argv0"); + if (!argv0) + 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) { + 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); + } else if (ty == XXPC_TYPE_ERROR) { + if (event == XXPC_ERROR_CONNECTION_INTERRUPTED) + return; + NSLog(@"XPC error from peer: %@", event); + } else { + NSLog(@"unknown object received from XPC (peer): %@", event); } - [out appendData:test]; - struct substituted_bundle_list_op op = {(uint16_t) len, - SUBSTITUTED_USE_DYLIB}; - [out appendBytes:&op length:sizeof(op)]; - [out appendData:dylib_path_data]; - static char zero = '\0'; - [out appendBytes:&zero length:1]; + }); + xxpc_connection_resume(peer); +} + +/* This is a daemon contacted by all processes which can load extensions. It + * currently does the work of reading the plists in + * /Library/Substitute/DynamicLibraries in order to avoid loading objc/CF + * libraries into the target binary (unless actually required by loaded + * libraries). In the future it will help with hot loading. */ + +int main() { + xxpc_connection_t listener = xxpc_connection_create_mach_service( + "com.ex.substituted", NULL, XXPC_CONNECTION_MACH_SERVICE_LISTENER); + if (!listener) { + NSLog(@"xxpc_connection_create_mach_service returned null"); + exit(1); } - the_bundle_list = out; - *bundle_list = [out bytes]; - *bundle_list_size = [out length]; + 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); + } else if (ty == XXPC_TYPE_ERROR) { + NSLog(@"XPC error in server: %@", object); + exit(1); + } else { + NSLog(@"unknown object received from XPC: %@", object); + } + }); + xxpc_connection_resume(listener); + [[NSRunLoop mainRunLoop] run]; } |