aboutsummaryrefslogtreecommitdiff
path: root/darwin-bootstrap/substituted.m
diff options
context:
space:
mode:
authorcomex2015-07-07 18:50:18 -0400
committercomex2015-07-07 18:54:34 -0400
commit2b6d33a8490c56612f207ecd51d0e2e272220642 (patch)
tree266c76fd4f073952fc4ca42553edc27836319411 /darwin-bootstrap/substituted.m
parentMerge branch 'mconfig-work' (diff)
downloadsubstitute-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];
}