diff options
author | comex | 2015-07-12 16:42:48 -0400 |
---|---|---|
committer | comex | 2015-07-12 16:44:58 -0400 |
commit | 41aefc7572abb3c689774354231217aaafe0b01a (patch) | |
tree | 610f0f38f5880d4577ca19e9ddb1084dfb7177ec | |
parent | how did that style violation get in there? must have been tired (diff) | |
download | substitute-41aefc7572abb3c689774354231217aaafe0b01a.tar.gz |
redo crash reporting - untested (but it compiles)
-rwxr-xr-x | configure | 4 | ||||
-rw-r--r-- | darwin-bootstrap/bundle-loader.c | 10 | ||||
-rw-r--r-- | darwin-bootstrap/posixspawn-hook.c | 137 | ||||
-rw-r--r-- | darwin-bootstrap/substituted.m | 119 | ||||
-rw-r--r-- | lib/cbit/htab.h | 54 | ||||
-rw-r--r-- | lib/darwin/xxpc.h | 8 |
6 files changed, 252 insertions, 80 deletions
@@ -57,7 +57,7 @@ if settings.enable_werror: settings[mach.name].cflags = ['-Werror'] + settings[mach.name].cflags for i in ('cflags', 'ldflags'): - settings.host[i] = ['-miphoneos-version-min=8.0'] + settings.host[i] + settings.host[i] = ['-miphoneos-version-min=8.0', '-O3'] + settings.host[i] # todo make overridable? cc_argv = c.cc.argv() @@ -212,7 +212,7 @@ if settings.enable_ios_bootstrap: ls = ['(out)/libsubstitute.dylib'] for ty, out, ins, objs, ldf, cf in [ - ('dylib', '(out)/posixspawn-hook.dylib', ['(src)/darwin-bootstrap/posixspawn-hook.c'], ls, [], []), + ('dylib', '(out)/posixspawn-hook.dylib', ['(src)/darwin-bootstrap/posixspawn-hook.c'], ls, ['-lbsm'], []), ('dylib', '(out)/bundle-loader.dylib', ['(src)/darwin-bootstrap/bundle-loader.c'], [], [], []), ('exec', '(out)/unrestrict', ['(src)/darwin-bootstrap/unrestrict.c'], ls, [], []), ('exec', '(out)/inject-into-launchd', ['(src)/darwin-bootstrap/inject-into-launchd.c'], ls, ['-framework', 'IOKit', '-framework', 'CoreFoundation'], []), diff --git a/darwin-bootstrap/bundle-loader.c b/darwin-bootstrap/bundle-loader.c index ed4dde4..7a90414 100644 --- a/darwin-bootstrap/bundle-loader.c +++ b/darwin-bootstrap/bundle-loader.c @@ -193,13 +193,6 @@ 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() { @@ -229,6 +222,7 @@ static void init() { ^(xxpc_object_t reply) { handle_xxpc_object(reply, true); }); + xxpc_release(message); /* Timing out *always* means a bug (or the user manually unloaded * substituted). Therefore, a high timeout is actually a good thing, @@ -272,8 +266,6 @@ static void init() { } xxpc_release(hello_reply); - atexit(inform_sud_of_clean_exit); - return; bad: 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 7c339f1..b2a7336 100644 --- a/darwin-bootstrap/posixspawn-hook.c +++ b/darwin-bootstrap/posixspawn-hook.c @@ -20,6 +20,8 @@ #include "ib-log.h" #include "substitute.h" #include "substitute-internal.h" +#include "darwin/xxpc.h" +#include "cbit/htab.h" #include <mach/mach.h> #include <mach-o/dyld.h> #include <mach-o/loader.h> @@ -30,15 +32,35 @@ #include <malloc/malloc.h> #include <errno.h> #include <arpa/inet.h> +#include <pthread.h> #include <libkern/OSByteOrder.h> +#define _pid_hash(pidp) (*(pidp)) +#define _pid_eq(pid1p, pid2p) (*(pid1p) == *(pid2p)) +#define _pid_null(pidp) (!*(pidp)) +DECL_STATIC_HTAB_KEY(pid_t, pid_t, _pid_hash, _pid_eq, _pid_null, 0); +DECL_HTAB(pid_str, pid_t, char *); + extern char ***_NSGetEnviron(void); -static __typeof__(posix_spawn) *old_posix_spawn, *old_posix_spawnp, - hook_posix_spawn, hook_posix_spawnp; +struct au_tid; +extern void audit_token_to_au32(audit_token_t, uid_t *, uid_t *, gid_t *, + uid_t *, gid_t *, pid_t *, pid_t *, + struct au_tid *); + +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 int (*old_xpc_pipe_try_receive)(mach_port_t, xxpc_object_t *, + mach_port_t *, void *, size_t, int); -static bool is_launchd; +static bool g_is_launchd; +static xxpc_object_t g_argv0_to_fate; +static HTAB_STORAGE(pid_str) g_pid_to_argv0 = + HTAB_STORAGE_INIT_STATIC(&g_pid_to_argv0, pid_str); +static pthread_mutex_t g_dicts_lock = PTHREAD_MUTEX_INITIALIZER; static bool advance(char **strp, const char *template) { size_t len = strlen(template); @@ -174,7 +196,7 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old, path, (flags & POSIX_SPAWN_SETEXEC) ? " (exec)" : "", (flags & POSIX_SPAWN_START_SUSPENDED) ? " (suspend)" : "", - is_launchd); + g_is_launchd); for (char *const *ap = argv; *ap; ap++) ib_log(" %s", *ap); } @@ -185,9 +207,11 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old, static const char psh_dylib[] = "/Library/Substitute/Helpers/posixspawn-hook.dylib"; + const char *argv0 = argv[0] ?: ""; + /* which dylib should we add, if any? */ const char *dylib_to_add; - if (is_launchd) { + if (g_is_launchd) { if (strcmp(path, "/usr/libexec/xpcproxy")) goto skip; dylib_to_add = psh_dylib; @@ -218,7 +242,7 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old, */ if (!strcmp(path, "/Library/Substitute/Helpers/substituted") || !strcmp(path, "/usr/sbin/notifyd") || - !strcmp(xbasename(argv[0] ?: ""), "sshd")) + !strcmp(xbasename(argv0), "sshd")) goto skip; dylib_to_add = bl_dylib; } @@ -354,6 +378,11 @@ static int hook_posix_spawn_generic(__typeof__(posix_spawn) *old, pid_t pid = *pidp; if (need_unrestrict) spawn_unrestrict(pid, !was_suspended, false); + + pthread_mutex_lock(&g_dicts_lock); + *htab_setp_pid_str(&g_pid_to_argv0.h, &pid, NULL) = strdup(argv0); + pthread_mutex_unlock(&g_dicts_lock); + goto cleanup; crap: ib_log("posixspawn-hook: weird error - OOM? skipping our stuff"); @@ -382,6 +411,95 @@ int hook_posix_spawnp(pid_t *restrict pid, const char *restrict path, attrp, argv, envp); } +static void after_wait_generic(pid_t pid, int stat) { + if (pid == -1) + return; + pthread_mutex_lock(&g_dicts_lock); + struct htab_bucket_pid_str *bucket = + htab_getbucket_pid_str(&g_pid_to_argv0.h, &pid); + if (!bucket) { + /* probably spawned some other way / not a task */ + if (IB_VERBOSE) + ib_log("reaped unknown pid %d", pid); + return; + } + char *argv0 = bucket->value; + xxpc_dictionary_set_int64(g_argv0_to_fate, argv0, stat); + free(argv0); + htab_removeat_pid_str(&g_pid_to_argv0.h, bucket); + pthread_mutex_unlock(&g_dicts_lock); +} + +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_xpc_pipe_try_receive(mach_port_t port_set, xxpc_object_t *requestp, + mach_port_t *recvp, void *mig_demux, + size_t msg_size, int dunno_ignored) { + int res = old_xpc_pipe_try_receive(port_set, requestp, recvp, mig_demux, + msg_size, dunno_ignored); + if (res) + return res; + xxpc_object_t request = *requestp; + if (!request || /* just to be sure */ + xxpc_get_type(request) != XXPC_TYPE_DICTIONARY) + return res; + /* is it for us? - usage of "in"/"out" is to satisfy the public vproc API */ + xxpc_object_t in = xxpc_dictionary_get_value(request, "in"); + if (!in || xxpc_get_type(in) != XXPC_TYPE_DICTIONARY) + return res; + const char *name = xxpc_dictionary_get_string(in, + "com.ex.substitute.hook-operation"); + if (!name) + return res; + /* is it from someone untrustworthy? */ + audit_token_t at; + xxpc_dictionary_get_audit_token(request, &at); + uid_t euid; + pid_t pid; + audit_token_to_au32(at, NULL, &euid, NULL, NULL, NULL, &pid, NULL, NULL); + if (euid != 0) { + ib_log("Attempt to perform hook-operation by pid %d with euid %d", + euid, pid); + return res; + } + xxpc_object_t reply = NULL; + if (!strcmp(name, "argv0-to-fate")) { + const char *argv0 = xxpc_dictionary_get_string(in, "argv0"); + if (!argv0) { + ib_log("invalid hook-operation message"); + return res; + } + reply = xxpc_dictionary_create_reply(request); + xxpc_object_t fate = xxpc_dictionary_get_value(g_argv0_to_fate, argv0); + if (fate) + xxpc_dictionary_set_value(reply, "out", fate); + } else { + ib_log("unknown hook-operation '%s'", name); + return res; + } + if (reply) { + int reply_res = xxpc_pipe_routine_reply(reply); + if (reply_res) { + ib_log("xxpc_pipe_routine_reply: %d", reply_res); + return res; + } + xxpc_release(reply); + } + xxpc_release(request); + *requestp = NULL; + return 0; +} + 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. */ @@ -438,9 +556,10 @@ static void init() { * (it also decreases the amount of library code necessary to load from * disk...) */ + g_argv0_to_fate = xxpc_dictionary_create(NULL, NULL, 0); const char *image0 = _dyld_get_image_name(0); - is_launchd = !!strstr(image0, "launchd"); + g_is_launchd = !!strstr(image0, "launchd"); struct substitute_image *im = substitute_open_image(image0); if (!im) { ib_log("posixspawn-hook: substitute_open_image failed"); @@ -451,6 +570,10 @@ static void init() { {"_posix_spawn", hook_posix_spawn, &old_posix_spawn}, {"_posix_spawnp", hook_posix_spawnp, &old_posix_spawnp}, {"_sandbox_check", hook_sandbox_check, &old_sandbox_check}, + {"_waitpid", hook_waitpid, &old_waitpid}, + {"_wait4", hook_wait4, &old_wait4}, + {"_xpc_pipe_try_receive", hook_xpc_pipe_try_receive, + &old_xpc_pipe_try_receive}, }; int err = substitute_interpose_imports(im, hooks, sizeof(hooks)/sizeof(*hooks), diff --git a/darwin-bootstrap/substituted.m b/darwin-bootstrap/substituted.m index 2c3217b..f03670c 100644 --- a/darwin-bootstrap/substituted.m +++ b/darwin-bootstrap/substituted.m @@ -3,6 +3,9 @@ #include "darwin/xxpc.h" #include "substitute.h" +void *vproc_swap_complex(void *vp, int key, xxpc_object_t inval, + __strong xxpc_object_t *outval); + /* 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 @@ -59,7 +62,7 @@ static xxpc_object_t nsstring_to_xpc(NSString *in) { @interface PeerHandler : NSObject { xxpc_object_t _connection; NSString *_argv0; - bool _is_springboard, _got_bye; + bool _is_springboard; } @end @@ -197,20 +200,77 @@ enum convert_filters_ret { return PROVISIONAL_PASS; } -- (bool)handleMessageHello:(xxpc_object_t)request { +- (void)updateSpringBoardNeedsSafe:(const char *)argv0 then:(void (^)())then { + xxpc_object_t inn = xxpc_dictionary_create(NULL, NULL, 0); + xxpc_dictionary_set_string(inn, "com.ex.substiute.hook-operation", + "argv0-to-fate"); + xxpc_dictionary_set_string(inn, "argv0", argv0); + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + ^{ + xxpc_object_t out = NULL; + vproc_swap_complex(NULL, 99999, inn, &out); + int to_set = REALLY_SAFE; + if (!out) { + NSLog(@"couldn't talk to launchd :( - assume worst case scenario"); + goto out; + } + if (xxpc_get_type(out) != XXPC_TYPE_INT64) { + NSLog(@"wrong type from launchd!?"); + goto out; + } + + int stat = (int) xxpc_int64_get_value(out); + bool crashed = WIFSIGNALED(stat) && WTERMSIG(stat) != SIGTERM; + if (crashed) { + if (g_springboard_needs_safe) { + NSLog(@"SpringBoard hung up more than once without without saying bye; using Really Safe Mode (no UI) next time :("); + to_set = REALLY_SAFE; + } else { + NSLog(@"SpringBoard hung up without saying bye; using safe mode next time."); + to_set = NEEDS_SAFE; + } + } else { + to_set = NO_SAFE; + } + + out: + dispatch_async(dispatch_get_main_queue(), ^{ + g_springboard_needs_safe = to_set; + then(); + }); + }); +} + +- (void)handleMessageHello:(NS_VALID_UNTIL_END_OF_SCOPE xxpc_object_t)request { + NSString *sb_exe = + @"/System/Library/CoreServices/SpringBoard.app/SpringBoard"; + if (_argv0 != NULL) - return false; + goto bad; const char *argv0 = xxpc_dictionary_get_string(request, "argv0"); if (!argv0) - return false; + goto bad; _argv0 = [NSString stringWithCString:argv0 encoding:NSUTF8StringEncoding]; - NSString *sb_exe = - @"/System/Library/CoreServices/SpringBoard.app/SpringBoard"; _is_springboard = [_argv0 isEqualToString:sb_exe]; + if (_is_springboard) + [self updateSpringBoardNeedsSafe:argv0 + then:^{[self handleMessageHelloRest:request];}]; + else + [self handleMessageHelloRest:request]; + return; + +bad: + [self handleBadMessage:request]; +} + +- (void)handleMessageHelloRest:(NS_VALID_UNTIL_END_OF_SCOPE + xxpc_object_t)request { + xxpc_object_t bundles = xxpc_array_create(NULL, 0); NSError *err; @@ -218,8 +278,6 @@ enum convert_filters_ret { NSArray *list = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:base error:&err]; - if (!list) - return bundles; for (NSString *dylib in list) { if (![[dylib pathExtension] isEqualToString:@"dylib"]) @@ -255,44 +313,23 @@ enum convert_filters_ret { 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) { - bool needs_safe = !_got_bye; - if (needs_safe) { - if (g_springboard_needs_safe) { - NSLog(@"SpringBoard hung up more than once without without saying bye; using Really Safe Mode (no UI) next time :("); - g_springboard_needs_safe = REALLY_SAFE; - } else { - NSLog(@"SpringBoard hung up without saying bye; using safe mode next time."); - g_springboard_needs_safe = NEEDS_SAFE; - } - } else { - g_springboard_needs_safe = NO_SAFE; - } - } +- (void)handleBadMessage:(xxpc_object_t)request { + NSLog(@"bad message received: %@", request); + xxpc_connection_cancel(_connection); } - -- (bool)handleMessage:(xxpc_object_t)request { +- (void)handleMessage:(NS_VALID_UNTIL_END_OF_SCOPE xxpc_object_t)request { const char *type = xxpc_dictionary_get_string(request, "type"); if (!type) - return false; + goto bad; if (!strcmp(type, "hello")) return [self handleMessageHello:request]; - else if (!strcmp(type, "bye")) - return [self handleMessageBye:request]; else - return false; + goto bad; +bad: + return [self handleBadMessage:request]; } - (instancetype)initWithConnection:(xxpc_object_t)connection { @@ -300,11 +337,10 @@ enum convert_filters_ret { xxpc_connection_set_event_handler(connection, ^(xxpc_object_t event) { xxpc_type_t ty = xxpc_get_type(event); if (ty == XXPC_TYPE_DICTIONARY) { - if (![self handleMessage:event]) - xxpc_connection_cancel(connection); + [self handleMessage:event]; } else if (ty == XXPC_TYPE_ERROR) { if (event == XXPC_ERROR_CONNECTION_INVALID) { - [self handleHangup]; + /* [self handleHangup]; */ } else { NSLog(@"XPC error from connection: %@", event); xxpc_connection_cancel(connection); @@ -322,7 +358,8 @@ int main() { NSLog(@"hello from substituted"); install_deadlock_warning(); xxpc_connection_t listener = xxpc_connection_create_mach_service( - "com.ex.substituted", NULL, XXPC_CONNECTION_MACH_SERVICE_LISTENER); + "com.ex.substituted", dispatch_get_main_queue(), + XXPC_CONNECTION_MACH_SERVICE_LISTENER); if (!listener) { NSLog(@"xxpc_connection_create_mach_service returned null"); exit(1); diff --git a/lib/cbit/htab.h b/lib/cbit/htab.h index ccb40b9..054b423 100644 --- a/lib/cbit/htab.h +++ b/lib/cbit/htab.h @@ -42,11 +42,11 @@ struct htab_internal { void *__htab_key_lookup_##name(struct htab_internal *restrict hi, \ const key_ty *restrict key, \ size_t entry_size, \ - bool add, bool resize_if_necessary); \ + bool add); \ func_decl \ - bool __htab_key_remove_##name(struct htab_internal *restrict hi, \ - const key_ty *restrict key, \ - size_t entry_size); \ + void __htab_key_removeat_##name(struct htab_internal *restrict hi, \ + void *op, \ + size_t entry_size); \ func_decl \ void __htab_key_memset_##name(void *ptr, size_t size); \ func_decl \ @@ -81,8 +81,8 @@ struct htab_internal { void *__htab_key_lookup_##name(struct htab_internal *restrict hi, \ const key_ty *restrict key, \ size_t entry_size, \ - bool add, bool resize_if_necessary) { \ - if (resize_if_necessary && \ + bool add) { \ + if (add && \ hi->capacity * 2 <= hi->length * 3) \ __htab_key_resize_##name(hi, hi->capacity * 2, entry_size); \ size_t capacity = hi->capacity; \ @@ -101,17 +101,14 @@ struct htab_internal { } \ if (eq_func(bucket, key)) \ return bucket; \ - } while ((i = (i + 1) % capacity) != hash); \ + } while (i = (i + 1) == capacity ? 0 : (i + 1), i != hash); \ return NULL; \ } \ \ /* slow but who cares */ \ - bool __htab_key_remove_##name(struct htab_internal *restrict hi, \ - const key_ty *restrict key, \ - size_t entry_size) { \ - void *op = __htab_key_lookup_##name(hi, key, entry_size, false, false); \ - if (!op) \ - return false; \ + void __htab_key_removeat_##name(struct htab_internal *restrict hi, \ + void *op, \ + size_t entry_size) { \ key_ty *orig = op; \ key_ty *end = (void *) ((char *) hi->base + hi->capacity * entry_size); \ key_ty *cur = orig; \ @@ -126,9 +123,8 @@ struct htab_internal { memmove(prev, cur, entry_size); \ prev = cur; \ } while (cur != orig); \ - memset(cur, 0, entry_size); \ + memset(cur, nil_byte, entry_size); \ hi->length--; \ - return true; \ } \ void __htab_key_memset_##name(void *ptr, size_t size) { \ memset(ptr, (nil_byte), size); \ @@ -152,7 +148,7 @@ struct htab_internal { if (!null_func(bucket)) { \ memcpy( \ __htab_key_lookup_##name(&temp, bucket, entry_size, \ - true, false), \ + true), \ bucket, \ entry_size); \ } \ @@ -199,7 +195,7 @@ struct htab_internal { bucket_ty *htab_getbucket_##name(htab_ty *restrict ht, \ const key_ty *restrict key) { \ return __htab_key_lookup_##key_name(&ht->hi, key, sizeof(bucket_ty), \ - false, true); \ + false); \ } \ UNUSED_STATIC_INLINE \ value_ty *htab_getp_##name(const htab_ty *restrict ht, \ @@ -211,7 +207,7 @@ struct htab_internal { bucket_ty *htab_setbucket_##name(htab_ty *restrict ht, \ const key_ty *restrict key) { \ return __htab_key_lookup_##key_name(&ht->hi, key, sizeof(bucket_ty), \ - true, true); \ + true); \ } \ UNUSED_STATIC_INLINE \ value_ty *htab_setp_##name(const htab_ty *restrict ht, \ @@ -231,7 +227,16 @@ struct htab_internal { } \ UNUSED_STATIC_INLINE \ bool htab_remove_##name(htab_ty *restrict ht, const key_ty *restrict key) { \ - return __htab_key_remove_##key_name(&ht->hi, key, sizeof(bucket_ty)); \ + void *op = __htab_key_lookup_##key_name(&ht->hi, key, sizeof(bucket_ty), \ + false); \ + if (!op) \ + return false; \ + __htab_key_removeat_##key_name(&ht->hi, op, sizeof(bucket_ty)); \ + return true; \ + } \ + UNUSED_STATIC_INLINE \ + void htab_removeat_##name(htab_ty *restrict ht, bucket_ty *op) { \ + __htab_key_removeat_##key_name(&ht->hi, op, sizeof(bucket_ty)); \ } \ UNUSED_STATIC_INLINE \ void __htab_memset_##name(void *ptr, size_t size) { \ @@ -263,12 +268,19 @@ struct htab_internal { #define HTAB_STORAGE_INIT(hs, name) do { \ struct htab_##name *h = &(hs)->h; \ h->length = 0; \ - h->capacity = (sizeof((hs)->rest) / sizeof(__htab_key_ty_##name)) + 1; \ + h->capacity = (sizeof((hs)->rest) / sizeof(struct htab_bucket_##name)) + 1; \ h->base = h->storage; \ __htab_memset_##name(h->base, \ - h->capacity * sizeof(__htab_key_ty_##name)); \ + h->capacity * sizeof(struct htab_bucket_##name)); \ } while (0) +/* only works if nil_byte is 0 */ +#define HTAB_STORAGE_INIT_STATIC(hs, name) \ + {{0, \ + (sizeof((hs)->rest) / sizeof(struct htab_bucket_##name)) + 1, \ + (hs)->h.storage \ + }} + #define HTAB_FOREACH(ht, key_var, val_var, name) \ LET(struct htab_##name *__htfe_ht = (ht)) \ for (size_t __htfe_bucket = 0; \ diff --git a/lib/darwin/xxpc.h b/lib/darwin/xxpc.h index 5caed15..4b5e175 100644 --- a/lib/darwin/xxpc.h +++ b/lib/darwin/xxpc.h @@ -3,6 +3,7 @@ * on OS X. */ #include <dispatch/dispatch.h> #include <os/object.h> +#include <mach/message.h> /* for audit_token_t */ #if OS_OBJECT_USE_OBJC #define DC_CAST (__bridge xxpc_object_t) @@ -23,6 +24,7 @@ DEFINE_CONST(XXPC_TYPE_ERROR, _xpc_type_error); DEFINE_CONST(XXPC_TYPE_DICTIONARY, _xpc_type_dictionary); DEFINE_CONST(XXPC_TYPE_ARRAY, _xpc_type_array); DEFINE_CONST(XXPC_TYPE_STRING, _xpc_type_string); +DEFINE_CONST(XXPC_TYPE_INT64, _xpc_type_int64); DEFINE_CONST(XXPC_ERROR_CONNECTION_INTERRUPTED, _xpc_error_connection_interrupted); DEFINE_CONST(XXPC_ERROR_CONNECTION_INVALID, @@ -44,6 +46,7 @@ char *WRAP(xpc_copy_description, (xxpc_object_t)); xxpc_type_t WRAP(xpc_get_type, (xxpc_object_t)); xxpc_object_t WRAP(xpc_string_create, (const char *)); const char *WRAP(xpc_string_get_string_ptr, (xxpc_object_t)); +int64_t WRAP(xpc_int64_get_value, (xxpc_object_t)); void WRAP(xpc_array_append_value, (xxpc_object_t, xxpc_object_t)); xxpc_object_t WRAP(xpc_array_create, (const xxpc_object_t *, size_t)); size_t WRAP(xpc_array_get_count, (const xxpc_object_t)); @@ -61,7 +64,10 @@ const char *WRAP(xpc_dictionary_get_string, (xxpc_object_t, const char *)); xxpc_object_t WRAP(xpc_dictionary_get_value, (xxpc_object_t, const char *)); void WRAP(xpc_dictionary_set_bool, (xxpc_object_t, const char *, bool)); void WRAP(xpc_dictionary_set_string, (xxpc_object_t, const char *, const char *)); +void WRAP(xpc_dictionary_set_uint64, (xxpc_object_t, const char *, uint64_t)); +void WRAP(xpc_dictionary_set_int64, (xxpc_object_t, const char *, int64_t)); void WRAP(xpc_dictionary_set_value, (xxpc_object_t, const char *, xxpc_object_t)); +void WRAP(xpc_dictionary_get_audit_token, (xxpc_object_t, audit_token_t *)); xxpc_connection_t WRAP(xpc_connection_create_mach_service, (const char *, dispatch_queue_t, @@ -72,6 +78,8 @@ void WRAP(xpc_connection_send_message_with_reply, (xxpc_connection_t, xxpc_object_t, dispatch_queue_t, xxpc_handler_t)); void WRAP(xpc_connection_send_message, (xxpc_connection_t, xxpc_object_t)); void WRAP(xpc_connection_cancel, (xxpc_connection_t)); +int WRAP(xpc_pipe_routine_reply, (xxpc_object_t)); + #undef DEFINE_TYPE #undef DEFINE_CONST |