├── framework
├── tests
├── framework
├── control
├── Makefile
└── tests.m
├── overlayheaders
├── .gitignore
├── layout
├── Library
│ ├── MobileSubstrate
│ │ └── DynamicLibraries
│ │ │ ├── RocketBootstrap.dylib
│ │ │ └── RocketBootstrap.plist
│ └── LaunchDaemons
│ │ └── com.rpetrich.rocketbootstrapd.plist
└── DEBIAN
│ ├── prerm
│ ├── postinst
│ └── control
├── defaultheaders
├── xpc
└── launch.h
├── fullheaders
├── xpc
└── launch.h
├── .gitmodules
├── entitlements.xml
├── log.h
├── libjailbreak_xpc.h
├── unfair_lock.h
├── rocketbootstrap_internal.h
├── rocketd_reenable.c
├── rocketd.c
├── rocketbootstrap.h
├── Makefile
├── rocketbootstrap_dynamic.h
├── sandbox.h
├── Shims.x
├── bootstrap.h
├── dispatch
└── mach_private.h
└── Tweak.x
/framework:
--------------------------------------------------------------------------------
1 | ../theos
--------------------------------------------------------------------------------
/tests/framework:
--------------------------------------------------------------------------------
1 | ../framework
--------------------------------------------------------------------------------
/overlayheaders:
--------------------------------------------------------------------------------
1 | ../overlayheaders/
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ._*
2 | *.deb
3 | .debmake
4 | _
5 | obj
6 | .theos
7 | .DS_Store
8 |
--------------------------------------------------------------------------------
/layout/Library/MobileSubstrate/DynamicLibraries/RocketBootstrap.dylib:
--------------------------------------------------------------------------------
1 | /usr/lib/librocketbootstrap.dylib
--------------------------------------------------------------------------------
/defaultheaders/xpc:
--------------------------------------------------------------------------------
1 | /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/xpc/
--------------------------------------------------------------------------------
/fullheaders/xpc:
--------------------------------------------------------------------------------
1 | /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/xpc/
--------------------------------------------------------------------------------
/defaultheaders/launch.h:
--------------------------------------------------------------------------------
1 | /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/launch.h
--------------------------------------------------------------------------------
/fullheaders/launch.h:
--------------------------------------------------------------------------------
1 | /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/launch.h
--------------------------------------------------------------------------------
/layout/DEBIAN/prerm:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | launchctl unload /Library/LaunchDaemons/com.rpetrich.rocketbootstrapd.plist || true
3 | launchctl stop com.apple.ReportCrash.SimulateCrash || true
4 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "framework"]
2 | path = framework
3 | url = git://github.com/rpetrich/theos.git
4 | [submodule "LightMessaging"]
5 | path = LightMessaging
6 | url = git://github.com/rpetrich/LightMessaging.git
7 |
--------------------------------------------------------------------------------
/entitlements.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | platform-application
5 |
6 | com.apple.private.skip-library-validation
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/control:
--------------------------------------------------------------------------------
1 | Package: com.rpetrich.rocketbootstrap.tests
2 | Depends: com.rpetrich.rocketbootstrap
3 | Name: RocketBootstrap Tests
4 | Version: 0.1
5 | Architecture: iphoneos-arm
6 | Description: Tests for RocketBootstrap
7 | Maintainer: BigBoss
8 | Author: Ryan Petrich
9 | Sponsor: thebigboss.org
10 | Section: Tweaks
11 | dev: rpetrich
12 |
--------------------------------------------------------------------------------
/log.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | // Tiny shim to convert NSLog to public os_log statements on iOS 10
4 | #ifdef __clang__
5 | #if __has_include()
6 | #include
7 | #define NSLog(...) do { \
8 | if (kCFCoreFoundationVersionNumber > 1299.0) { \
9 | @autoreleasepool { \
10 | os_log(OS_LOG_DEFAULT, "%{public}@", [NSString stringWithFormat:__VA_ARGS__]); \
11 | } \
12 | } else { \
13 | NSLog(__VA_ARGS__); \
14 | } \
15 | } while(0)
16 | #endif
17 | #endif
18 |
--------------------------------------------------------------------------------
/layout/Library/MobileSubstrate/DynamicLibraries/RocketBootstrap.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Filter
6 |
7 | Executables
8 |
9 | ReportCrash
10 |
11 | CoreFoundationVersion
12 |
13 | 800
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/layout/DEBIAN/postinst:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | chown root:wheel /Library/LaunchDaemons/com.rpetrich.rocketbootstrapd.plist
3 | launchctl load /Library/LaunchDaemons/com.rpetrich.rocketbootstrapd.plist || true
4 | launchctl stop com.apple.ReportCrash.SimulateCrash || true
5 | mv /System/Library/LaunchDaemons{BAK,}/com.apple.ReportCrash.SimulateCrash.plist 2> /dev/null || true
6 | launchctl load /System/Library/LaunchDaemons/com.apple.ReportCrash.SimulateCrash.plist 2> /dev/null || true
7 | chown root:wheel /usr/libexec/_rocketd_reenable
8 | chmod +s /usr/libexec/_rocketd_reenable
9 |
--------------------------------------------------------------------------------
/tests/Makefile:
--------------------------------------------------------------------------------
1 | LIBRARY_NAME = librocketbootstrap_tests
2 | librocketbootstrap_tests_FILES = tests.m
3 | librocketbootstrap_tests_LIBRARIES = rocketbootstrap
4 | librocketbootstrap_tests_FRAMEWORKS = Foundation UIKit
5 |
6 | ADDITIONAL_CFLAGS = -std=c99 -I../
7 |
8 | IPHONE_ARCHS = armv6 arm64
9 |
10 | SDKVERSION_armv6 = 5.1
11 | INCLUDE_SDKVERSION_armv6 = 8.4
12 | TARGET_IPHONEOS_DEPLOYMENT_VERSION = 4.0
13 |
14 | TARGET_IPHONEOS_DEPLOYMENT_VERSION_armv6 = 3.0
15 | THEOS_PLATFORM_SDK_ROOT_armv6 = /Applications/Xcode_Legacy.app/Contents/Developer
16 |
17 | include framework/makefiles/common.mk
18 | include framework/makefiles/library.mk
19 |
--------------------------------------------------------------------------------
/layout/DEBIAN/control:
--------------------------------------------------------------------------------
1 | Package: com.rpetrich.rocketbootstrap
2 | Depends: mobilesubstrate (>= 0.9.5000), firmware (>= 3.0)
3 | Name: RocketBootstrap
4 | Version: 1.0.9
5 | Architecture: iphoneos-arm
6 | Description: Support library allowing tweaks to communicate with sandboxed processes
7 | Depiction: https://www.rpetrich.com/cydia/rocketbootstrap/beta/
8 | Homepage: https://www.rpetrich.com/cydia/rocketbootstrap/beta/
9 | Maintainer: BigBoss
10 | Author: Ryan Petrich
11 | Sponsor: thebigboss.org
12 | Section: Tweaks
13 | dev: rpetrich
14 | Tag: purpose::extension, role::developer
15 |
--------------------------------------------------------------------------------
/layout/Library/LaunchDaemons/com.rpetrich.rocketbootstrapd.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ProgramArguments
6 |
7 | /usr/libexec/rocketd
8 |
9 | OnDemand
10 |
11 | UserName
12 | mobile
13 | MachServices
14 |
15 | com.rpetrich.rocketbootstrapd
16 |
17 |
18 | Label
19 | com.rpetrich.rocketbootstrapd
20 | JetsamProperties
21 |
22 | JetsamPriority
23 | 18
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/libjailbreak_xpc.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | /* Flags for entp command. Any combination or none can be specified. */
5 | /* Wait for xpcproxy to exec before continuing */
6 | #define FLAG_WAIT_EXEC (1 << 5)
7 | /* Wait for 0.5 sec after acting */
8 | #define FLAG_DELAY (1 << 4)
9 | /* Send SIGCONT after acting */
10 | #define FLAG_SIGCONT (1 << 3)
11 | /* Set sandbox exception */
12 | #define FLAG_SANDBOX (1 << 2)
13 | /* Set platform binary flag */
14 | #define FLAG_PLATFORMIZE (1 << 1)
15 | /* Set basic entitlements */
16 | #define FLAG_ENTITLE (1)
17 |
18 | typedef void *jb_connection_t;
19 |
20 | #if __BLOCKS__
21 | typedef void (^jb_callback_t)(int result);
22 |
23 | /* These ones run asynchronously. Callbacks take 1 on success, 0 on failure.
24 | The queue which they run on is undefined. */
25 | extern void jb_entitle(jb_connection_t connection, pid_t pid, uint32_t what, jb_callback_t done);
26 | extern void jb_fix_setuid(jb_connection_t connection, pid_t pid, jb_callback_t done);
27 | #endif
28 |
29 | extern jb_connection_t jb_connect(void);
30 | extern void jb_disconnect(jb_connection_t connection);
31 |
32 | extern int jb_entitle_now(jb_connection_t connection, pid_t pid, uint32_t what);
33 | extern int jb_fix_setuid_now(jb_connection_t connection, pid_t pid);
34 |
35 | extern void jb_oneshot_entitle_now(pid_t pid, uint32_t what);
36 | extern void jb_oneshot_fix_setuid_now(pid_t pid);
37 |
--------------------------------------------------------------------------------
/unfair_lock.h:
--------------------------------------------------------------------------------
1 | #if __IPHONE_OS_VERSION_MAX_ALLOWED > 100000
2 | // New SDK
3 | #include
4 | #define unfair_lock os_unfair_lock
5 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000
6 | // Only targeting new iOS, always use unfair locks
7 | #define unfair_lock_lock os_unfair_lock_lock
8 | #define unfair_lock_trylock os_unfair_lock_trylock
9 | #define unfair_lock_unlock os_unfair_lock_unlock
10 | #else
11 | // Support both at runtime
12 | #import
13 | static inline void unfair_lock_lock(unfair_lock *lock)
14 | {
15 | if (&os_unfair_lock_lock != NULL) {
16 | os_unfair_lock_lock(lock);
17 | } else {
18 | OSSpinLockLock((volatile OSSpinLock *)lock);
19 | }
20 | }
21 | static inline bool unfair_lock_trylock(unfair_lock *lock)
22 | {
23 | if (&os_unfair_lock_trylock != NULL) {
24 | return os_unfair_lock_trylock(lock);
25 | } else {
26 | return OSSpinLockTry((volatile OSSpinLock *)lock);
27 | }
28 | }
29 | static inline void unfair_lock_unlock(unfair_lock *lock)
30 | {
31 | if (&os_unfair_lock_unlock != NULL) {
32 | os_unfair_lock_unlock(lock);
33 | } else {
34 | OSSpinLockUnlock((volatile OSSpinLock *)lock);
35 | }
36 | }
37 | #endif
38 | #else
39 | // Old SDK, fallback to using regular old spinlocks
40 | #import
41 | #define unfair_lock volatile OSSpinLock
42 | #define unfair_lock_lock OSSpinLockLock
43 | #define unfair_lock_trylock OSSpinLockTry
44 | #define unfair_lock_unlock OSSpinLockUnlock
45 | #endif
--------------------------------------------------------------------------------
/rocketbootstrap_internal.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | #import "rocketbootstrap.h"
5 |
6 | #define kRocketBootstrapUnlockService "com.rpetrich.rocketbootstrapd"
7 |
8 | #define ROCKETBOOTSTRAP_LOOKUP_ID -1
9 |
10 | typedef struct {
11 | mach_msg_header_t head;
12 | mach_msg_body_t body;
13 | uint32_t name_length;
14 | char name[];
15 | } _rocketbootstrap_lookup_query_t;
16 |
17 | typedef struct {
18 | mach_msg_header_t head;
19 | mach_msg_body_t body;
20 | mach_msg_port_descriptor_t response_port;
21 | } _rocketbootstrap_lookup_response_t;
22 |
23 | #import "LightMessaging/LightMessaging.h"
24 |
25 | __attribute__((unused))
26 | static LMConnection connection = {
27 | MACH_PORT_NULL,
28 | kRocketBootstrapUnlockService
29 | };
30 |
31 | __attribute__((unused))
32 | static inline bool rocketbootstrap_is_passthrough(void)
33 | {
34 | return kCFCoreFoundationVersionNumber < 800.0;
35 | }
36 |
37 | __attribute__((unused))
38 | static inline bool rocketbootstrap_uses_name_redirection(void)
39 | {
40 | if (kCFCoreFoundationVersionNumber >= 1556.00) {
41 | static int state;
42 | int currentState = state;
43 | if (currentState == 0) {
44 | int check = sandbox_check(getpid(), "mach-lookup", SANDBOX_FILTER_LOCAL_NAME | SANDBOX_CHECK_NO_REPORT, "cy:rbs");
45 | currentState = check == 0 ? 1 : 2;
46 | }
47 | return currentState - 1;
48 | }
49 | return false;
50 | }
51 |
52 | kern_return_t _rocketbootstrap_is_unlocked(const name_t service_name); // Errors if not in a privileged process such as SpringBoard or backboardd
53 |
--------------------------------------------------------------------------------
/rocketd_reenable.c:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import
4 |
5 | #ifdef __LP64__
6 | #if __has_include()
7 | #include
8 | #define sign_function(ptr) ({ \
9 | __typeof__(ptr) _ptr = ptr; \
10 | ptr ? ptrauth_sign_unauthenticated(_ptr, ptrauth_key_function_pointer, 0) : _ptr; \
11 | })
12 | #else
13 | #define sign_function(ptr) ptr
14 | #endif
15 | #else
16 | #define sign_function(ptr) ptr
17 | #endif
18 |
19 | #ifdef __arm64__
20 | #import "libjailbreak_xpc.h"
21 | static int fix_setuid(void)
22 | {
23 | void *libjailbreak = dlopen("/usr/lib/libjailbreak.dylib", RTLD_LAZY);
24 | if (libjailbreak) {
25 | jb_connection_t (*jb_connect)(void) = sign_function(dlsym(libjailbreak, "jb_connect"));
26 | int (*jb_fix_setuid_now)(jb_connection_t connection, pid_t pid) = sign_function(dlsym(libjailbreak, "jb_fix_setuid_now"));
27 | void (*jb_disconnect)(jb_connection_t connection) = sign_function(dlsym(libjailbreak, "jb_disconnect"));
28 | if (jb_connect && jb_fix_setuid_now && jb_disconnect) {
29 | jb_connection_t connection = jb_connect();
30 | if (connection) {
31 | int result = jb_fix_setuid_now(connection, getpid());
32 | jb_disconnect(connection);
33 | return result;
34 | }
35 | }
36 | }
37 | return 1;
38 | }
39 | #else
40 | static int fix_setuid(void)
41 | {
42 | // Does not apply to older iOS versions
43 | return 1;
44 | }
45 | #endif
46 |
47 | int main(int argc, char *argv[])
48 | {
49 | close(0);
50 | close(1);
51 | close(2);
52 | fix_setuid();
53 | setuid(0);
54 | setgid(0);
55 | seteuid(0);
56 | setegid(0);
57 | return execlp("launchctl", "launchctl", "load", "/Library/LaunchDaemons/com.rpetrich.rocketbootstrapd.plist", NULL);
58 | }
59 |
--------------------------------------------------------------------------------
/tests/tests.m:
--------------------------------------------------------------------------------
1 | #import
2 | #include "log.h"
3 |
4 | #import "rocketbootstrap.h"
5 |
6 | @implementation NSObject (rocketbootstrap)
7 |
8 | + (kern_return_t)rocketbootstrap_unlock:(NSString *)name
9 | {
10 | return rocketbootstrap_unlock([name UTF8String]);
11 | }
12 |
13 | static CFDataRef messagePortCallback(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info)
14 | {
15 | NSLog(@"rockettest_messageport_server: received %@", data);
16 | return CFDataCreate(kCFAllocatorDefault, (const UInt8 *)"bootstrap", 9);
17 | }
18 |
19 | + (kern_return_t)rockettest_messageport_server
20 | {
21 | static CFMessagePortRef messagePort;
22 | if (messagePort)
23 | return 0;
24 | messagePort = CFMessagePortCreateLocal(kCFAllocatorDefault, CFSTR("rockettest_messageport"), messagePortCallback, NULL, NULL);
25 | CFRunLoopSourceRef source = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, messagePort, 0);
26 | CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
27 | CFRunLoopAddSource(CFRunLoopGetCurrent(), source, (CFStringRef)UITrackingRunLoopMode);
28 | return rocketbootstrap_cfmessageportexposelocal(messagePort);
29 | }
30 |
31 | + (NSData *)rockettest_messageport_client
32 | {
33 | CFMessagePortRef remote = rocketbootstrap_cfmessageportcreateremote(kCFAllocatorDefault, CFSTR("rockettest_messageport"));
34 | if (!remote)
35 | return nil;
36 | CFDataRef request = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)"rocket", 6);
37 | CFDataRef response = NULL;
38 | CFMessagePortSendRequest(remote, 0, request, 10, 10, CFSTR("rocketboostrap_wait"), &response);
39 | CFRelease(remote);
40 | CFRelease(request);
41 | return [(NSData *)response autorelease];
42 | }
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/rocketd.c:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #define LIGHTMESSAGING_USE_ROCKETBOOTSTRAP 0
4 |
5 | #import "rocketbootstrap_internal.h"
6 |
7 | static CFMutableSetRef allowedNames;
8 |
9 | static const uint32_t one = 1;
10 |
11 | static void machPortCallback(CFMachPortRef port, void *bytes, CFIndex size, void *info)
12 | {
13 | LMMessage *request = bytes;
14 | if (!LMDataWithSizeIsValidMessage(bytes, size)) {
15 | LMSendReply(request->head.msgh_remote_port, NULL, 0);
16 | LMResponseBufferFree(bytes);
17 | return;
18 | }
19 | // Send Response
20 | const void *data = LMMessageGetData(request);
21 | size_t length = LMMessageGetDataLength(request);
22 | const void *reply_data = NULL;
23 | uint32_t reply_length = 0;
24 | if (length) {
25 | CFStringRef name = CFStringCreateWithBytes(kCFAllocatorDefault, data, length, kCFStringEncodingUTF8, false);
26 | if (name) {
27 | switch (request->head.msgh_id) {
28 | case 0: // Register
29 | #ifdef DEBUG
30 | CFLog(kCFLogLevelWarning, CFSTR("Unlocking %@"), name);
31 | #endif
32 | CFSetAddValue(allowedNames, name);
33 | break;
34 | case 1: // Query
35 | if (CFSetContainsValue(allowedNames, name)) {
36 | reply_data = &one;
37 | reply_length = sizeof one;
38 | #ifdef DEBUG
39 | CFLog(kCFLogLevelWarning, CFSTR("Queried %@, is unlocked"), name);
40 | #endif
41 | } else {
42 | #ifdef DEBUG
43 | CFLog(kCFLogLevelWarning, CFSTR("Queried %@, is locked!"), name);
44 | #endif
45 | }
46 | break;
47 | case 2:
48 | // Good morning, still awake
49 | reply_data = &one;
50 | reply_length = sizeof one;
51 | break;
52 | }
53 | CFRelease(name);
54 | }
55 | }
56 | LMSendReply(request->head.msgh_remote_port, reply_data, reply_length);
57 | LMResponseBufferFree(bytes);
58 | }
59 |
60 | int main(int argc, char *argv[])
61 | {
62 | if (rocketbootstrap_is_passthrough()) {
63 | return 0;
64 | }
65 | allowedNames = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
66 | LMCheckInService(connection.serverName, CFRunLoopGetCurrent(), machPortCallback, NULL);
67 | notify_post("com.rpetrich.rocketd.started");
68 | CFRunLoopRun();
69 | return 0;
70 | }
71 |
--------------------------------------------------------------------------------
/rocketbootstrap.h:
--------------------------------------------------------------------------------
1 | #ifndef ROCKETBOOTSTRAP_H
2 | #define ROCKETBOOTSTRAP_H
3 |
4 | #include
5 | #include
6 | #include "bootstrap.h"
7 |
8 | __BEGIN_DECLS
9 | #ifndef ROCKETBOOTSTRAP_LOAD_DYNAMIC
10 |
11 | // Look up a port by service name
12 | kern_return_t rocketbootstrap_look_up(mach_port_t bootstrap_port, const name_t service_name, mach_port_t *out_service_port);
13 |
14 | // Grant system-wide access to a particular service name
15 | // Note: Will return an error if called from within a sandboxed process
16 | kern_return_t rocketbootstrap_unlock(const name_t service_name);
17 | // Register a port with and grant system-wide access to a particular service name
18 | // Note: Will return an error if called from within a sandboxed process
19 | kern_return_t rocketbootstrap_register(mach_port_t bootstrap_port, name_t service_name, mach_port_t service_port);
20 |
21 |
22 | // CFMessagePort helpers
23 |
24 | #ifdef __COREFOUNDATION_CFMESSAGEPORT__
25 | // Acquire access to a system-wide CFMessagePort service
26 | CFMessagePortRef rocketbootstrap_cfmessageportcreateremote(CFAllocatorRef allocator, CFStringRef name);
27 | // Expose access to a CFMessagePort service
28 | // Note: Will return an error if called from within a sandboxed process
29 | kern_return_t rocketbootstrap_cfmessageportexposelocal(CFMessagePortRef messagePort);
30 | #endif
31 |
32 |
33 | // CPDistributedMessagingCenter helpers
34 |
35 | #ifdef __OBJC__
36 | // Unlock access to a system-wide CPDistributedMessagingCenter service
37 | // Note: Server processes may only run inside privileged processes
38 | @class CPDistributedMessagingCenter;
39 | void rocketbootstrap_distributedmessagingcenter_apply(CPDistributedMessagingCenter *messaging_center);
40 | #endif
41 |
42 |
43 | // XPC helpers
44 |
45 | #ifdef __XPC_CONNECTION_H__
46 | // Create an XPC connection representing a system-wide service
47 | // flags should be XPC_CONNECTION_MACH_SERVICE_LISTENER for a listener connection, and 0 for a client client connection
48 | // XPC_CONNECTION_MACH_SERVICE_LISTENER will return an error if called from within a sandboxed process
49 | // 0 will return an error if the service name hasn't been registered
50 | xpc_connection_t rocketbootstrap_xpc_connection_create(const char *name, dispatch_queue_t targetq, uint64_t flags);
51 | // Copy the application bundle identifier of the peer connection
52 | xpc_object_t rocketbootstrap_xpc_connection_copy_application_identifier(xpc_connection_t connection);
53 | #endif
54 |
55 |
56 | #else
57 | #include "rocketbootstrap_dynamic.h"
58 | #endif
59 | __END_DECLS
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | LIBRARY_NAME = librocketbootstrap
2 | librocketbootstrap_FILES = Tweak.x Shims.x
3 | librocketbootstrap_LIBRARIES = substrate
4 | librocketbootstrap_FRAMEWORKS = Foundation
5 | librocketbootstrap_USE_MODULES = 0
6 |
7 | TOOL_NAME = rocketd _rocketd_reenable
8 | rocketd_FILES = rocketd.c
9 | rocketd_CFLAGS = -fblocks
10 | rocketd_FRAMEWORKS = CoreFoundation
11 | rocketd_INSTALL_PATH = /usr/libexec
12 | rocketd_USE_MODULES = 0
13 | rocketd_CODESIGN_FLAGS = -Sentitlements.xml
14 |
15 | _rocketd_reenable_FILES = rocketd_reenable.c
16 | _rocketd_reenable_INSTALL_PATH = /usr/libexec
17 | _rocketd_reenable_USE_MODULES = 0
18 | _rocketd_reenable_CODESIGN_FLAGS = -Sentitlements.xml
19 |
20 | ADDITIONAL_CFLAGS = -std=c99 -Ioverlayheaders
21 |
22 | # Support targeting 3.0 in packaged builds, but allow testing packages/builds to be missing support for old iOS versions
23 | XCODE4_PATH ?= /Applications/Xcode_Legacy.app
24 | XCODE6_PATH ?= /Volumes/Xcode/Xcode.app
25 | XCODE9_PATH ?= /Volumes/Xcode_9.4.1/Xcode.app
26 |
27 | ifeq ($(wildcard $(XCODE4_PATH)/.*),)
28 | ADDITIONAL_CFLAGS += -Idefaultheaders
29 | IPHONE_ARCHS = armv7 armv7s arm64 arm64e
30 | TARGET_IPHONEOS_DEPLOYMENT_VERSION = 8.4
31 | ifeq ($(FINALPACKAGE),1)
32 | $(error Building final package requires a legacy Xcode install!)
33 | endif
34 | else
35 | armv6_CFLAGS += -Ifullheaders
36 | armv7_CFLAGS += -Ifullheaders
37 | armv7s_CFLAGS += -Ifullheaders
38 | arm64_CFLAGS += -Idefaultheaders
39 | arm64e_CFLAGS += -Idefaultheaders
40 | rocketd_IPHONE_ARCHS = armv6 arm64
41 | _rocketd_reenable_IPHONE_ARCHS = armv6 arm64
42 | IPHONE_ARCHS = armv6 armv7 armv7s arm64 arm64e
43 | SDKVERSION_armv6 = 5.1
44 | INCLUDE_SDKVERSION_armv6 = 8.4
45 | TARGET_IPHONEOS_DEPLOYMENT_VERSION_armv6 = 3.0
46 | TARGET_IPHONEOS_DEPLOYMENT_VERSION_armv7 = 4.0
47 | TARGET_IPHONEOS_DEPLOYMENT_VERSION_armv7s = 6.0
48 | TARGET_IPHONEOS_DEPLOYMENT_VERSION_arm64 = 7.0
49 | TARGET_IPHONEOS_DEPLOYMENT_VERSION_arm64e = 12.0
50 | TARGET_IPHONEOS_DEPLOYMENT_VERSION = 9.0
51 | THEOS_PLATFORM_SDK_ROOT_armv6 = $(XCODE4_PATH)/Contents/Developer
52 | THEOS_PLATFORM_SDK_ROOT_armv7 = $(XCODE6_PATH)/Contents/Developer
53 | THEOS_PLATFORM_SDK_ROOT_armv7s = $(XCODE6_PATH)/Contents/Developer
54 | THEOS_PLATFORM_SDK_ROOT_arm64 = $(XCODE9_PATH)/Contents/Developer
55 | endif
56 |
57 | include framework/makefiles/common.mk
58 | include framework/makefiles/library.mk
59 | include framework/makefiles/tool.mk
60 |
61 | stage::
62 | mkdir -p "$(THEOS_STAGING_DIR)/usr/include"
63 | cp -a rocketbootstrap.h rocketbootstrap_dynamic.h "$(THEOS_STAGING_DIR)/usr/include"
64 | plutil -convert binary1 "$(THEOS_STAGING_DIR)/Library/MobileSubstrate/DynamicLibraries/RocketBootstrap.plist"
65 | plutil -convert binary1 "$(THEOS_STAGING_DIR)/Library/LaunchDaemons/com.rpetrich.rocketbootstrapd.plist"
66 |
--------------------------------------------------------------------------------
/rocketbootstrap_dynamic.h:
--------------------------------------------------------------------------------
1 | // DONT INCLUDE DIRECTLY
2 | // Set ROCKETBOOTSTRAP_LOAD_DYNAMIC and then include rocketbootstrap.h
3 | #include
4 |
5 | #if __has_include()
6 | #include
7 |
8 | __attribute__((unused))
9 | static void *_rocketbootstrap_dlsym_func(const char *name) {
10 | void *handle = dlopen("/usr/lib/librocketbootstrap.dylib", RTLD_LAZY);
11 | if (handle) {
12 | void *result = dlsym(handle, name);
13 | if (result) {
14 | return ptrauth_sign_unauthenticated(ptrauth_strip(result, ptrauth_key_function_pointer), ptrauth_key_function_pointer, 0);
15 | }
16 | }
17 | return NULL;
18 | }
19 |
20 | #else
21 |
22 | __attribute__((unused))
23 | static void *_rocketbootstrap_dlsym_func(const char *name) {
24 | void *handle = dlopen("/usr/lib/librocketbootstrap.dylib", RTLD_LAZY);
25 | if (handle) {
26 | return dlsym(handle, name);
27 | }
28 | return NULL;
29 | }
30 |
31 | #endif
32 |
33 | __attribute__((unused))
34 | static kern_return_t rocketbootstrap_look_up(mach_port_t bp, const name_t service_name, mach_port_t *sp)
35 | {
36 | static kern_return_t (*impl)(mach_port_t bp, const name_t service_name, mach_port_t *sp);
37 | if (!impl) {
38 | impl = _rocketbootstrap_dlsym_func("rocketbootstrap_look_up");
39 | if (!impl) {
40 | impl = bootstrap_look_up;
41 | }
42 | }
43 | return impl(bp, service_name, sp);
44 | }
45 |
46 | __attribute__((unused))
47 | static kern_return_t rocketbootstrap_unlock(const name_t service_name)
48 | {
49 | static kern_return_t (*impl)(const name_t service_name);
50 | if (!impl) {
51 | impl = _rocketbootstrap_dlsym_func("rocketbootstrap_unlock");
52 | if (!impl) {
53 | return -1;
54 | }
55 | }
56 | return impl(service_name);
57 | }
58 |
59 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
60 | __attribute__((unused))
61 | static kern_return_t rocketbootstrap_register(mach_port_t bp, name_t service_name, mach_port_t sp)
62 | {
63 | static kern_return_t (*impl)(mach_port_t bp, name_t service_name, mach_port_t sp);
64 | if (!impl) {
65 | impl = _rocketbootstrap_dlsym_func("rocketbootstrap_register");
66 | if (!impl) {
67 | impl = bootstrap_register;
68 | }
69 | }
70 | return impl(bp, service_name, sp);
71 | }
72 | #pragma GCC diagnostic warning "-Wdeprecated-declarations"
73 |
74 | #ifdef __COREFOUNDATION_CFMESSAGEPORT__
75 | __attribute__((unused))
76 | static CFMessagePortRef rocketbootstrap_cfmessageportcreateremote(CFAllocatorRef allocator, CFStringRef name)
77 | {
78 | static CFMessagePortRef (*impl)(CFAllocatorRef allocator, CFStringRef name);
79 | if (!impl) {
80 | impl = _rocketbootstrap_dlsym_func("rocketbootstrap_cfmessageportcreateremote");
81 | if (!impl) {
82 | impl = CFMessagePortCreateRemote;
83 | }
84 | }
85 | return impl(allocator, name);
86 | }
87 | __attribute__((unused))
88 | static kern_return_t rocketbootstrap_cfmessageportexposelocal(CFMessagePortRef messagePort)
89 | {
90 | static kern_return_t (*impl)(CFMessagePortRef messagePort);
91 | if (!impl) {
92 | impl = _rocketbootstrap_dlsym_func("rocketbootstrap_cfmessageportexposelocal");
93 | if (!impl) {
94 | return -1;
95 | }
96 | }
97 | return impl(messagePort);
98 | }
99 | #endif
100 |
101 | #ifdef __OBJC__
102 | @class CPDistributedMessagingCenter;
103 | __attribute__((unused))
104 | static void rocketbootstrap_distributedmessagingcenter_apply(CPDistributedMessagingCenter *messaging_center)
105 | {
106 | static void (*impl)(CPDistributedMessagingCenter *messagingCenter);
107 | if (!impl) {
108 | impl = _rocketbootstrap_dlsym_func("rocketbootstrap_distributedmessagingcenter_apply");
109 | if (!impl)
110 | return;
111 | }
112 | impl(messaging_center);
113 | }
114 | #endif
115 |
116 | #ifdef __XPC_CONNECTION_H__
117 | __attribute__((unused))
118 | static xpc_connection_t rocketbootstrap_xpc_connection_create(const char *name, dispatch_queue_t targetq, uint64_t flags)
119 | {
120 | static xpc_connection_t (*impl)(const char *name, dispatch_queue_t targetq, uint64_t flags);
121 | if (!impl) {
122 | impl = _rocketbootstrap_dlsym_func("rocketbootstrap_xpc_connection_create");
123 | if (!impl)
124 | return NULL;
125 | }
126 | return impl(name, targetq, flags);
127 | }
128 |
129 | __attribute__((unused))
130 | static xpc_object_t rocketbootstrap_xpc_connection_copy_application_identifier(xpc_connection_t connection)
131 | {
132 | static xpc_object_t (*impl)(xpc_connection_t connection);
133 | if (!impl) {
134 | impl = _rocketbootstrap_dlsym_func("rocketbootstrap_xpc_connection_copy_application_identifier");
135 | if (!impl)
136 | return NULL;
137 | }
138 | return impl(connection);
139 | }
140 | #endif
141 |
--------------------------------------------------------------------------------
/sandbox.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2006-2010 Apple Inc. All rights reserved.
3 | *
4 | * @APPLE_LICENSE_HEADER_START@
5 | *
6 | * This file contains Original Code and/or Modifications of Original Code
7 | * as defined in and that are subject to the Apple Public Source License
8 | * Version 2.0 (the 'License'). You may not use this file except in
9 | * compliance with the License. Please obtain a copy of the License at
10 | * http://www.opensource.apple.com/apsl/ and read it before using this
11 | * file.
12 | *
13 | * The Original Code and all software distributed under the License are
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 | * Please see the License for the specific language governing rights and
19 | * limitations under the License.
20 | *
21 | * @APPLE_LICENSE_HEADER_END@
22 | */
23 | #ifndef _SANDBOX_H_
24 | #define _SANDBOX_H_
25 |
26 | #include
27 | #include
28 | #include
29 |
30 | __BEGIN_DECLS
31 | /*
32 | * @function sandbox_init
33 | * Places the current process in a sandbox with a profile as
34 | * specified. If the process is already in a sandbox, the new profile
35 | * is ignored and sandbox_init() returns an error.
36 | *
37 | * @param profile (input) The Sandbox profile to be used. The format
38 | * and meaning of this parameter is modified by the `flags' parameter.
39 | *
40 | * @param flags (input) Must be SANDBOX_NAMED. All other
41 | * values are reserved.
42 | *
43 | * @param errorbuf (output) In the event of an error, sandbox_init
44 | * will set `*errorbuf' to a pointer to a NUL-terminated string
45 | * describing the error. This string may contain embedded newlines.
46 | * This error information is suitable for developers and is not
47 | * intended for end users.
48 | *
49 | * If there are no errors, `*errorbuf' will be set to NULL. The
50 | * buffer `*errorbuf' should be deallocated with `sandbox_free_error'.
51 | *
52 | * @result 0 on success, -1 otherwise.
53 | */
54 | int sandbox_init(const char *profile, uint64_t flags, char **errorbuf);
55 |
56 | /*
57 | * @define SANDBOX_NAMED The `profile' argument specifies a Sandbox
58 | * profile named by one of the kSBXProfile* string constants.
59 | */
60 | #define SANDBOX_NAMED 0x0001
61 |
62 | #ifdef __APPLE_API_PRIVATE
63 |
64 | /* The following flags are reserved for Mac OS X. Developers should not
65 | * depend on their availability.
66 | */
67 |
68 | /*
69 | * @define SANDBOX_NAMED_BUILTIN The `profile' argument specifies the
70 | * name of a builtin profile that is statically compiled into the
71 | * system.
72 | */
73 | #define SANDBOX_NAMED_BUILTIN 0x0002
74 |
75 | /*
76 | * @define SANDBOX_NAMED_EXTERNAL The `profile' argument specifies the
77 | * pathname of a Sandbox profile. The pathname may be abbreviated: If
78 | * the name does not start with a `/' it is treated as relative to
79 | * /usr/share/sandbox and a `.sb' suffix is appended.
80 | */
81 | #define SANDBOX_NAMED_EXTERNAL 0x0003
82 |
83 | /*
84 | * @define SANDBOX_NAMED_MASK Mask for name types: 4 bits, 15 possible
85 | * name types, 3 currently defined.
86 | */
87 | #define SANDBOX_NAMED_MASK 0x000f
88 |
89 | #endif /* __APPLE_API_PRIVATE */
90 |
91 | /*
92 | * Available Sandbox profiles.
93 | */
94 |
95 | /* TCP/IP networking is prohibited. */
96 | extern const char kSBXProfileNoInternet[];
97 |
98 | /* All sockets-based networking is prohibited. */
99 | extern const char kSBXProfileNoNetwork[];
100 |
101 | /* File system writes are prohibited. */
102 | extern const char kSBXProfileNoWrite[];
103 |
104 | /* File system writes are restricted to temporary folders /var/tmp and
105 | * confstr(_CS_DARWIN_USER_DIR, ...).
106 | */
107 | extern const char kSBXProfileNoWriteExceptTemporary[];
108 |
109 | /* All operating system services are prohibited. */
110 | extern const char kSBXProfilePureComputation[];
111 |
112 | /*
113 | * @function sandbox_free_error
114 | * Deallocates an error string previously allocated by sandbox_init.
115 | *
116 | * @param errorbuf (input) The buffer to be freed. Must be a pointer
117 | * previously returned by sandbox_init in the `errorbuf' argument, or NULL.
118 | *
119 | * @result void
120 | */
121 | void sandbox_free_error(char *errorbuf);
122 |
123 |
124 | #ifdef __APPLE_API_PRIVATE
125 |
126 | /* The following definitions are reserved for Mac OS X. Developers should not
127 | * depend on their availability.
128 | */
129 |
130 | int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf);
131 |
132 | int sandbox_init_with_extensions(const char *profile, uint64_t flags, const char *const extensions[], char **errorbuf);
133 |
134 | enum sandbox_filter_type {
135 | SANDBOX_FILTER_NONE,
136 | SANDBOX_FILTER_PATH,
137 | SANDBOX_FILTER_GLOBAL_NAME,
138 | SANDBOX_FILTER_LOCAL_NAME,
139 | SANDBOX_FILTER_APPLEEVENT_DESTINATION,
140 | SANDBOX_FILTER_RIGHT_NAME,
141 | };
142 |
143 | extern const enum sandbox_filter_type SANDBOX_CHECK_NO_REPORT __attribute__((weak_import));
144 |
145 | enum sandbox_extension_flags {
146 | FS_EXT_DEFAULTS = 0,
147 | FS_EXT_FOR_PATH = (1 << 0),
148 | FS_EXT_FOR_FILE = (1 << 1),
149 | FS_EXT_READ = (1 << 2),
150 | FS_EXT_WRITE = (1 << 3),
151 | FS_EXT_PREFER_FILEID = (1 << 4),
152 | };
153 |
154 | int sandbox_check(pid_t pid, const char *operation, enum sandbox_filter_type type, ...);
155 |
156 | int sandbox_note(const char *note);
157 |
158 | int sandbox_suspend(pid_t pid);
159 | int sandbox_unsuspend(void);
160 |
161 | int sandbox_issue_extension(const char *path, char **ext_token);
162 | int sandbox_issue_fs_extension(const char *path, uint64_t flags, char **ext_token);
163 | int sandbox_issue_fs_rw_extension(const char *path, char **ext_token);
164 | int sandbox_issue_mach_extension(const char *name, char **ext_token);
165 |
166 | int sandbox_consume_extension(const char *path, const char *ext_token);
167 | int sandbox_consume_fs_extension(const char *ext_token, char **path);
168 | int sandbox_consume_mach_extension(const char *ext_token, char **name);
169 |
170 | int sandbox_release_fs_extension(const char *ext_token);
171 |
172 | int sandbox_container_path_for_pid(pid_t pid, char *buffer, size_t bufsize);
173 |
174 | int sandbox_wakeup_daemon(char **errorbuf);
175 |
176 | const char *_amkrtemp(const char *);
177 |
178 | #endif /* __APPLE_API_PRIVATE */
179 |
180 | __END_DECLS
181 | #endif /* _SANDBOX_H_ */
182 |
--------------------------------------------------------------------------------
/Shims.x:
--------------------------------------------------------------------------------
1 | #import "log.h"
2 | #import "unfair_lock.h"
3 | #import "rocketbootstrap_internal.h"
4 |
5 | #import
6 | #import
7 | #import
8 |
9 | static unfair_lock shim_lock;
10 |
11 | kern_return_t bootstrap_look_up3(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, const uuid_t instance_id, uint64_t flags) __attribute__((weak_import));
12 | static kern_return_t (*_bootstrap_look_up3)(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, const uuid_t instance_id, uint64_t flags);
13 |
14 | static kern_return_t $bootstrap_look_up3(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, const uuid_t instance_id, uint64_t flags)
15 | {
16 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
17 | NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
18 | id obj = [threadDictionary objectForKey:@"rocketbootstrap_intercept_next_lookup"];
19 | if (obj) {
20 | [threadDictionary removeObjectForKey:@"rocketbootstrap_intercept_next_lookup"];
21 | [pool drain];
22 | return rocketbootstrap_look_up(bp, service_name, sp);
23 | }
24 | [pool drain];
25 | return _bootstrap_look_up3(bp, service_name, sp, target_pid, instance_id, flags);
26 | }
27 |
28 | static void hook_bootstrap_lookup(void)
29 | {
30 | static bool hooked_bootstrap_look_up;
31 | unfair_lock_lock(&shim_lock);
32 | if (!hooked_bootstrap_look_up) {
33 | MSHookFunction(bootstrap_look_up3, $bootstrap_look_up3, (void **)&_bootstrap_look_up3);
34 | hooked_bootstrap_look_up = true;
35 | }
36 | unfair_lock_unlock(&shim_lock);
37 | }
38 |
39 | CFMessagePortRef rocketbootstrap_cfmessageportcreateremote(CFAllocatorRef allocator, CFStringRef name)
40 | {
41 | if (rocketbootstrap_is_passthrough())
42 | return CFMessagePortCreateRemote(allocator, name);
43 | hook_bootstrap_lookup();
44 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
45 | NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
46 | [threadDictionary setObject:(id)kCFBooleanTrue forKey:@"rocketbootstrap_intercept_next_lookup"];
47 | CFMessagePortRef result = CFMessagePortCreateRemote(allocator, name);
48 | [threadDictionary removeObjectForKey:@"rocketbootstrap_intercept_next_lookup"];
49 | [pool drain];
50 | return result;
51 | }
52 |
53 | kern_return_t rocketbootstrap_cfmessageportexposelocal(CFMessagePortRef messagePort)
54 | {
55 | if (rocketbootstrap_is_passthrough())
56 | return 0;
57 | CFStringRef name = CFMessagePortGetName(messagePort);
58 | if (!name)
59 | return -1;
60 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
61 | kern_return_t result = rocketbootstrap_unlock([(NSString *)name UTF8String]);
62 | [pool drain];
63 | return result;
64 | }
65 |
66 | @interface CPDistributedMessagingCenter : NSObject
67 | - (void)_setupInvalidationSource;
68 | @end
69 |
70 | %group messaging_center
71 |
72 | static bool has_hooked_messaging_center;
73 |
74 | %hook CPDistributedMessagingCenter
75 |
76 | - (mach_port_t)_sendPort
77 | {
78 | if (objc_getAssociatedObject(self, &has_hooked_messaging_center)) {
79 | mach_port_t *_sendPort = CHIvarRef(self, _sendPort, mach_port_t);
80 | NSLock **_lock = CHIvarRef(self, _lock, NSLock *);
81 | if (_sendPort && _lock) {
82 | [*_lock lock];
83 | mach_port_t result = *_sendPort;
84 | if (result == MACH_PORT_NULL) {
85 | NSString **_centerName = CHIvarRef(self, _centerName, NSString *);
86 | if (_centerName && *_centerName && [self respondsToSelector:@selector(_setupInvalidationSource)]) {
87 | mach_port_t bootstrap = MACH_PORT_NULL;
88 | task_get_bootstrap_port(mach_task_self(), &bootstrap);
89 | rocketbootstrap_look_up(bootstrap, [*_centerName UTF8String], _sendPort);
90 | [self _setupInvalidationSource];
91 | result = *_sendPort;
92 | }
93 | }
94 | [*_lock unlock];
95 | return result;
96 | }
97 | }
98 | return %orig();
99 | }
100 |
101 | - (void)runServerOnCurrentThreadProtectedByEntitlement:(id)entitlement
102 | {
103 | %orig();
104 | if (objc_getAssociatedObject(self, &has_hooked_messaging_center)) {
105 | NSString **_centerName = CHIvarRef(self, _centerName, NSString *);
106 | if (_centerName && *_centerName) {
107 | rocketbootstrap_unlock([*_centerName UTF8String]);
108 | }
109 | }
110 | }
111 |
112 | %end
113 |
114 | %end
115 |
116 | void rocketbootstrap_distributedmessagingcenter_apply(CPDistributedMessagingCenter *messaging_center)
117 | {
118 | if (rocketbootstrap_is_passthrough())
119 | return;
120 | unfair_lock_lock(&shim_lock);
121 | if (!has_hooked_messaging_center) {
122 | has_hooked_messaging_center = true;
123 | %init(messaging_center);
124 | }
125 | unfair_lock_unlock(&shim_lock);
126 | objc_setAssociatedObject(messaging_center, &has_hooked_messaging_center, (id)kCFBooleanTrue, OBJC_ASSOCIATION_ASSIGN);
127 | }
128 |
129 | #ifdef __clang__
130 |
131 | #ifndef __IPHONE_9_0
132 | #define __IPHONE_9_0 90000
133 | #define __AVAILABILITY_INTERNAL__IPHONE_9_0
134 | #endif
135 |
136 | #include
137 |
138 | static xpc_endpoint_t _xpc_endpoint_create(mach_port_t port)
139 | {
140 | static xpc_endpoint_t(*__xpc_endpoint_create)(mach_port_t);
141 | if (!__xpc_endpoint_create) {
142 | MSImageRef libxpc = MSGetImageByName("/usr/lib/system/libxpc.dylib");
143 | if (!libxpc) {
144 | return NULL;
145 | }
146 | __xpc_endpoint_create = MSFindSymbol(libxpc, "__xpc_endpoint_create");
147 | if (!__xpc_endpoint_create) {
148 | return NULL;
149 | }
150 | }
151 | return __xpc_endpoint_create(port);
152 | }
153 |
154 | static mach_port_t _xpc_connection_copy_listener_port(xpc_connection_t connection)
155 | {
156 | static mach_port_t(*__xpc_connection_copy_listener_port)(xpc_connection_t);
157 | if (!__xpc_connection_copy_listener_port) {
158 | MSImageRef libxpc = MSGetImageByName("/usr/lib/system/libxpc.dylib");
159 | if (!libxpc) {
160 | return MACH_PORT_NULL;
161 | }
162 | __xpc_connection_copy_listener_port = MSFindSymbol(libxpc, "__xpc_connection_copy_listener_port");
163 | if (!__xpc_connection_copy_listener_port) {
164 | return MACH_PORT_NULL;
165 | }
166 | }
167 | return __xpc_connection_copy_listener_port(connection);
168 | }
169 |
170 | xpc_object_t xpc_connection_copy_entitlement_value(xpc_connection_t, const char* entitlement);
171 |
172 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
173 | xpc_connection_t rocketbootstrap_xpc_connection_create(const char *name, dispatch_queue_t targetq, uint64_t flags)
174 | {
175 | mach_port_t bootstrap = MACH_PORT_NULL;
176 | if (task_get_bootstrap_port(mach_task_self(), &bootstrap) != 0) {
177 | return NULL;
178 | }
179 | if (flags & XPC_CONNECTION_MACH_SERVICE_LISTENER) {
180 | xpc_connection_t result = xpc_connection_create(NULL, targetq);
181 | mach_port_t port = _xpc_connection_copy_listener_port(result);
182 | if (rocketbootstrap_register(bootstrap, (char *)name, port) != 0) {
183 | xpc_release(result);
184 | return NULL;
185 | }
186 | return result;
187 | }
188 | mach_port_t send_port = MACH_PORT_NULL;
189 | if (rocketbootstrap_look_up(bootstrap, name, &send_port) != 0) {
190 | return NULL;
191 | }
192 | xpc_endpoint_t endpoint = _xpc_endpoint_create(send_port);
193 | xpc_connection_t result = xpc_connection_create_from_endpoint(endpoint);
194 | xpc_release(endpoint);
195 | if (targetq != NULL) {
196 | xpc_connection_set_target_queue(result, targetq);
197 | }
198 | return result;
199 | }
200 |
201 | xpc_object_t rocketbootstrap_xpc_connection_copy_application_identifier(xpc_connection_t connection)
202 | {
203 | xpc_object_t application_id = xpc_connection_copy_entitlement_value(connection, "application-identifier");
204 | if (!application_id) {
205 | return NULL;
206 | }
207 | if (xpc_get_type(application_id) != XPC_TYPE_STRING) {
208 | xpc_release(application_id);
209 | return NULL;
210 | }
211 | xpc_object_t team_id = xpc_connection_copy_entitlement_value(connection, "com.apple.developer.team-identifier");
212 | if (!team_id) {
213 | return application_id;
214 | }
215 | if (xpc_get_type(team_id) != XPC_TYPE_STRING) {
216 | xpc_release(team_id);
217 | return application_id;
218 | }
219 | const char *application_id_str = xpc_string_get_string_ptr(application_id);
220 | const char *team_id_str = xpc_string_get_string_ptr(team_id);
221 | size_t team_id_length = xpc_string_get_length(team_id);
222 | if (memcmp(application_id_str, team_id_str, team_id_length) != 0 || application_id_str[team_id_length] != '.') {
223 | xpc_release(team_id);
224 | return application_id;
225 | }
226 | xpc_object_t trimmed_id = xpc_string_create(application_id_str + team_id_length + 1);
227 | xpc_release(team_id);
228 | xpc_release(application_id);
229 | return trimmed_id;
230 | }
231 |
232 | #endif
233 |
--------------------------------------------------------------------------------
/bootstrap.h:
--------------------------------------------------------------------------------
1 | #ifndef __BOOTSTRAP_H__
2 | #define __BOOTSTRAP_H__
3 | /*
4 | * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved.
5 | *
6 | * @APPLE_APACHE_LICENSE_HEADER_START@
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | *
20 | * @APPLE_APACHE_LICENSE_HEADER_END@
21 | */
22 |
23 | /*
24 | * bootstrap -- fundamental service initiator and port server
25 | * Mike DeMoney, NeXT, Inc.
26 | * Copyright, 1990. All rights reserved.
27 | */
28 |
29 | /*
30 | * Interface: Bootstrap server
31 | *
32 | * The bootstrap server is the first user-mode task initiated by the Mach
33 | * kernel at system boot time. The bootstrap server provides two services,
34 | * it initiates other system tasks, and manages a table of name-port bindings
35 | * for fundamental system services (e.g. lookupd, Window Manager, etc...).
36 | *
37 | * Name-port bindings can be established with the bootstrap server by either
38 | * of two mechanisms:
39 | *
40 | * 1. The binding can be indicated, in advance of the service that backs it
41 | * being available, via a "service create" request. In this case, bootstrap
42 | * will immediately create a port and bind the indicated name with that port.
43 | * At a later time, a service may "checkin" for the name-port
44 | * binding and will be returned receive rights for the bound port. Lookup's
45 | * on bindings created by this mechanism will return send rights to the port,
46 | * even if no service has "checked-in". In this case, requests sent to the
47 | * bound port will be queued until a server has checked-in and can satisfy the
48 | * request.
49 | *
50 | * 2. Bindings can be established dynamically via a "register" request. In
51 | * this case, the register request provides bootstrap with a name and send
52 | * rights for a port. Bootstrap will provide send rights for the bound port
53 | * to any requestor via the lookup request.
54 | *
55 | * Bootstrap provides its service port to descendant tasks via the Mach
56 | * "bootstrap" special task port. All direct descendants of bootstrap receive
57 | * a "privileged" bootstrap service port. System services that initiate
58 | * untrusted tasks should replace the Mach bootstrap task special port with
59 | * a subset bootstrap port to prevent them from infecting the namespace.
60 | *
61 | * The bootstrap server creates a "backup" port for each service that it
62 | * creates. This is used to detect when a checked out service is no longer
63 | * being served. The bootstrap server regains all rights to the port and
64 | * it is marked available for check-out again. This allows crashed servers to
65 | * resume service to previous clients. Lookup's on this named port will
66 | * continue to be serviced by bootstrap while holding receive rights for the
67 | * bound port. A client may detect that the service is inactive via the
68 | * bootstrap status request. If an inactive service re-registers rather
69 | * than "checking-in" the original bound port is destroyed.
70 | *
71 | * The status of a named service may be obtained via the "status" request.
72 | * A service is "active" if a name-port binding exists and receive rights
73 | * to the bound port are held by a task other than bootstrap.
74 | *
75 | * The bootstrap server may also (re)start server processes associated with
76 | * with a set of services. The definition of the server process is done
77 | * through the "create server" request. The server will be launched in the
78 | * same bootstrap context in which it was registered.
79 | */
80 | #include
81 | #include
82 | #include
83 | #include
84 | #include
85 | #include
86 |
87 | __BEGIN_DECLS
88 |
89 | #pragma GCC visibility push(default)
90 |
91 | #define BOOTSTRAP_MAX_NAME_LEN 128
92 | #define BOOTSTRAP_MAX_CMD_LEN 512
93 |
94 | typedef char name_t[BOOTSTRAP_MAX_NAME_LEN];
95 | typedef char cmd_t[BOOTSTRAP_MAX_CMD_LEN];
96 | typedef name_t *name_array_t;
97 | typedef int bootstrap_status_t;
98 | typedef bootstrap_status_t *bootstrap_status_array_t;
99 | typedef unsigned int bootstrap_property_t;
100 | typedef bootstrap_property_t * bootstrap_property_array_t;
101 |
102 | typedef boolean_t *bool_array_t;
103 |
104 | #define BOOTSTRAP_MAX_LOOKUP_COUNT 20
105 |
106 | #define BOOTSTRAP_SUCCESS 0
107 | #define BOOTSTRAP_NOT_PRIVILEGED 1100
108 | #define BOOTSTRAP_NAME_IN_USE 1101
109 | #define BOOTSTRAP_UNKNOWN_SERVICE 1102
110 | #define BOOTSTRAP_SERVICE_ACTIVE 1103
111 | #define BOOTSTRAP_BAD_COUNT 1104
112 | #define BOOTSTRAP_NO_MEMORY 1105
113 | #define BOOTSTRAP_NO_CHILDREN 1106
114 |
115 | #define BOOTSTRAP_STATUS_INACTIVE 0
116 | #define BOOTSTRAP_STATUS_ACTIVE 1
117 | #define BOOTSTRAP_STATUS_ON_DEMAND 2
118 |
119 | /*
120 | * After main() starts, it is safe to assume that this variable is always set.
121 | */
122 | extern mach_port_t bootstrap_port;
123 |
124 | /*
125 | * bootstrap_create_server()
126 | *
127 | * Declares a server that mach_init will re-spawn within the specified
128 | * bootstrap context. The server is considered already "active"
129 | * (i.e. will not be re-spawned) until the returned server_port is
130 | * deallocated.
131 | *
132 | * In the meantime, services can be declared against the server,
133 | * by using the server_port as the privileged bootstrap target of
134 | * subsequent bootstrap_create_service() calls.
135 | *
136 | * When mach_init re-spawns the server, its task bootstrap port
137 | * is set to the privileged sever_port. Through this special
138 | * bootstrap port, it can access all of parent bootstrap's context
139 | * (and all services are created in the parent's namespace). But
140 | * all additional service declarations (and declaration removals)
141 | * will be associated with this particular server.
142 | *
143 | * Only a holder of the server_port privilege bootstrap port can
144 | * check in or register over those services.
145 | *
146 | * When all services associated with a server are deleted, and the server
147 | * exits, it will automatically be deleted itself.
148 | *
149 | * If the server is declared "on_demand," then a non-running server
150 | * will be re-launched on first use of one of the service ports
151 | * registered against it. Otherwise, it will be re-launched
152 | * immediately upon exiting (whether any client is actively using
153 | * any of the service ports or not).
154 | *
155 | * Errors: Returns appropriate kernel errors on rpc failure.
156 | * Returns BOOTSTRAP_NOT_PRIVILEGED, bootstrap or uid invalid.
157 | */
158 | kern_return_t bootstrap_create_server(
159 | mach_port_t bp,
160 | cmd_t server_cmd,
161 | uid_t server_uid,
162 | boolean_t on_demand,
163 | mach_port_t *server_port);
164 |
165 | /*
166 | * bootstrap_subset()
167 | *
168 | * Returns a new port to use as a bootstrap port. This port behaves
169 | * exactly like the previous bootstrap_port, except that ports dynamically
170 | * registered via bootstrap_register() are available only to users of this
171 | * specific subset_port. Lookups on the subset_port will return ports
172 | * registered with this port specifically, and ports registered with
173 | * ancestors of this subset_port. Duplications of services already
174 | * registered with an ancestor port may be registered with the subset port
175 | * are allowed. Services already advertised may then be effectively removed
176 | * by registering PORT_NULL for the service.
177 | * When it is detected that the requestor_port is destroyed the subset
178 | * port and all services advertized by it are destroyed as well.
179 | *
180 | * Errors: Returns appropriate kernel errors on rpc failure.
181 | */
182 | kern_return_t bootstrap_subset(
183 | mach_port_t bp,
184 | mach_port_t requestor_port,
185 | mach_port_t *subset_port);
186 |
187 | /*
188 | * bootstrap_unprivileged()
189 | *
190 | * Given a bootstrap port, return its unprivileged equivalent. If
191 | * the port is already unprivileged, another reference to the same
192 | * port is returned.
193 | *
194 | * This is most often used by servers, which are launched with their
195 | * bootstrap port set to the privileged port for the server, to get
196 | * an unprivileged version of the same port for use by its unprivileged
197 | * children (or any offspring that it does not want to count as part
198 | * of the "server" for mach_init registration and re-launch purposes).
199 | *
200 | * Native launchd jobs are always started with an unprivileged port.
201 | */
202 | kern_return_t bootstrap_unprivileged(
203 | mach_port_t bp,
204 | mach_port_t *unpriv_port)
205 | AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
206 |
207 | /*
208 | * bootstrap_parent()
209 | *
210 | * Given a bootstrap subset port, return the parent bootstrap port.
211 | * If the specified bootstrap port is already the root subset,
212 | * the same port will be returned. Much like "." and ".." are the same
213 | * in the file system name space for the root directory ("/").
214 | *
215 | * Errors:
216 | * Returns BOOTSTRAP_NOT_PRIVILEGED if the caller is not running
217 | * with an effective user id of root (as determined by the security
218 | * token in the message trailer).
219 | */
220 | kern_return_t bootstrap_parent(
221 | mach_port_t bp,
222 | mach_port_t *parent_port);
223 |
224 | /*
225 | * bootstrap_register()
226 | *
227 | * Registers a send right for service_port with the service identified by
228 | * service_name. Attempts to register a service where an active binding
229 | * already exists are rejected.
230 | *
231 | * If the service was previously declared with bootstrap_create_service(),
232 | * but is not currently active, this call can be used to undeclare the
233 | * service. The bootstrap port used must have sufficient privilege to
234 | * do so. (Registering MACH_PORT_NULL is especially useful for shutting
235 | * down declared services).
236 | *
237 | * This API is deprecated. Old scenarios and recommendations:
238 | *
239 | * 1) Code that used to call bootstrap_check_in() and then bootstrap_register()
240 | * can now always call bootstrap_check_in().
241 | *
242 | * 2) If the code was registering a well known name, please switch to launchd.
243 | *
244 | * 3) If the code was registering a dynamically generated string and passing
245 | * the string to other applications, please rewrite the code to send a Mach
246 | * send-right directly.
247 | *
248 | * 4) If the launchd job maintained an optional Mach service, please reserve
249 | * the name with launchd and control the presense of the service through
250 | * ownership of the Mach receive right like so.
251 | *
252 | * MachServices
253 | *
254 | * com.apple.windowserver
255 | *
256 | * com.apple.windowserver.active
257 | *
258 | * HideUntilCheckIn
259 | *
260 | *
261 | *
262 | *
263 | *
264 | * Errors: Returns appropriate kernel errors on rpc failure.
265 | * Returns BOOTSTRAP_NOT_PRIVILEGED, if request directed to
266 | * bootstrap port without privilege.
267 | * Returns BOOTSTRAP_NAME_IN_USE, if service has already been
268 | * register or checked-in.
269 | */
270 | AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5
271 | kern_return_t
272 | bootstrap_register(mach_port_t bp, name_t service_name, mach_port_t sp);
273 |
274 | /*
275 | * bootstrap_create_service()
276 | *
277 | * Creates a service named "service_name" and returns a send right to that
278 | * port in "service_port." The port may later be checked in as if this
279 | * port were configured in the bootstrap configuration file.
280 | *
281 | * This API is deprecated. Please call bootstrap_check_in() instead.
282 | *
283 | * Errors: Returns appropriate kernel errors on rpc failure.
284 | * Returns BOOTSTRAP_SERVICE_ACTIVE, if service already exists.
285 | */
286 | #ifdef AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6
287 | AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6
288 | #endif
289 | kern_return_t
290 | bootstrap_create_service(mach_port_t bp, name_t service_name, mach_port_t *sp);
291 |
292 | /*
293 | * bootstrap_check_in()
294 | *
295 | * Returns the receive right for the service named by service_name. The
296 | * service must have been declared in the launchd.plist(5) file associated
297 | * with the job. Attempts to check_in a service which is already active
298 | * are not allowed.
299 | *
300 | * If the service was declared as being associated with a server, the
301 | * check_in must come from the server's privileged port (server_port).
302 | *
303 | * Errors: Returns appropriate kernel errors on rpc failure.
304 | * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
305 | * Returns BOOTSTRAP_NOT_PRIVILEGED, if request directed to
306 | * bootstrap port without privilege.
307 | * Returns BOOTSTRAP_SERVICE_ACTIVE, if service has already been
308 | * registered or checked-in.
309 | */
310 | kern_return_t bootstrap_check_in(
311 | mach_port_t bp,
312 | const name_t service_name,
313 | mach_port_t *sp);
314 |
315 | /*
316 | * bootstrap_look_up()
317 | *
318 | * Returns a send right for the service port declared/registered under the
319 | * name service_name. The service is not guaranteed to be active. Use the
320 | * bootstrap_status call to determine the status of the service.
321 | *
322 | * Errors: Returns appropriate kernel errors on rpc failure.
323 | * Returns BOOTSTRAP_UNKNOWN_SERVICE, if service does not exist.
324 | */
325 | kern_return_t bootstrap_look_up(
326 | mach_port_t bp,
327 | const name_t service_name,
328 | mach_port_t *sp);
329 |
330 | /*
331 | * bootstrap_status()
332 | *
333 | * In practice, this call was used to preflight whether the following two
334 | * APIs would succeed.
335 | *
336 | * bootstrap_look_up()
337 | * bootstrap_check_in()
338 | *
339 | * Please don't bother. Just call the above two APIs directly and check
340 | * for failure.
341 | */
342 | kern_return_t bootstrap_status(
343 | mach_port_t bp,
344 | name_t service_name,
345 | bootstrap_status_t *service_active)
346 | AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
347 |
348 | /* bootstrap_strerror()
349 | *
350 | * Translate a return value from the bootstrap_*() APIs to a string.
351 | */
352 | const char *bootstrap_strerror(kern_return_t r) __attribute__((__nothrow__, __pure__, __warn_unused_result__));
353 |
354 | #pragma GCC visibility pop
355 |
356 | __END_DECLS
357 |
358 | #endif /* __BOOTSTRAP_H__ */
--------------------------------------------------------------------------------
/dispatch/mach_private.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
3 | *
4 | * @APPLE_APACHE_LICENSE_HEADER_START@
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * @APPLE_APACHE_LICENSE_HEADER_END@
19 | */
20 |
21 | /*
22 | * IMPORTANT: This header file describes INTERNAL interfaces to libdispatch
23 | * which are subject to change in future releases of Mac OS X. Any applications
24 | * relying on these interfaces WILL break.
25 | */
26 |
27 | #ifndef __DISPATCH_MACH_PRIVATE__
28 | #define __DISPATCH_MACH_PRIVATE__
29 |
30 | #ifndef __DISPATCH_INDIRECT__
31 | #error "Please #include instead of this file directly."
32 | #include // for HeaderDoc
33 | #endif
34 |
35 | __BEGIN_DECLS
36 |
37 | #if DISPATCH_MACH_SPI
38 |
39 | #include
40 |
41 | /*!
42 | * @functiongroup Dispatch Mach Channel SPI
43 | *
44 | * IMPORTANT: This is Libsystem-internal SPI not intended for general use and
45 | * is subject to change at any time without warning.
46 | */
47 |
48 | /*!
49 | * @typedef dispatch_mach_t
50 | * A dispatch mach channel asynchronously recevives and sends mach messages.
51 | */
52 | DISPATCH_DECL(dispatch_mach);
53 |
54 | /*!
55 | * @typedef dispatch_mach_reason_t
56 | * Reasons for a mach channel handler to be invoked.
57 | *
58 | * @const DISPATCH_MACH_CONNECTED
59 | * The channel has been connected. The first handler invocation on a channel
60 | * after calling dispatch_mach_connect() will have this reason.
61 | *
62 | * @const DISPATCH_MACH_MESSAGE_RECEIVED
63 | * A message was received, it is passed in the message parameter.
64 | *
65 | * @const DISPATCH_MACH_MESSAGE_SENT
66 | * A message was sent, it is passed in the message parameter (so that associated
67 | * resources can be disposed of).
68 | *
69 | * @const DISPATCH_MACH_MESSAGE_SEND_FAILED
70 | * A message failed to be sent, it is passed in the message parameter (so that
71 | * associated resources can be disposed of), along with the error code from
72 | * mach_msg().
73 | *
74 | * @const DISPATCH_MACH_MESSAGE_NOT_SENT
75 | * A message was not sent due to the channel being canceled or reconnected, it
76 | * is passed in the message parameter (so that associated resources can be
77 | * disposed of).
78 | *
79 | * @const DISPATCH_MACH_BARRIER_COMPLETED
80 | * A barrier block has finished executing.
81 | *
82 | * @const DISPATCH_MACH_DISCONNECTED
83 | * The channel has been disconnected by a call to dispatch_mach_reconnect() or
84 | * dispatch_mach_cancel(), an empty message is passed in the message parameter
85 | * (so that associated port rights can be disposed of).
86 | * The message header will contain either a remote port with a previously
87 | * connected send right, or a local port with a previously connected receive
88 | * right (if the channel was canceled), or a local port with a receive right
89 | * that was being monitored for a direct reply to a message previously sent to
90 | * the channel (if no reply was received).
91 | *
92 | * @const DISPATCH_MACH_CANCELED
93 | * The channel has been canceled.
94 | */
95 | DISPATCH_ENUM(dispatch_mach_reason, unsigned long,
96 | DISPATCH_MACH_CONNECTED = 1,
97 | DISPATCH_MACH_MESSAGE_RECEIVED,
98 | DISPATCH_MACH_MESSAGE_SENT,
99 | DISPATCH_MACH_MESSAGE_SEND_FAILED,
100 | DISPATCH_MACH_MESSAGE_NOT_SENT,
101 | DISPATCH_MACH_BARRIER_COMPLETED,
102 | DISPATCH_MACH_DISCONNECTED,
103 | DISPATCH_MACH_CANCELED,
104 | DISPATCH_MACH_REASON_LAST, /* unused */
105 | );
106 |
107 | /*!
108 | * @typedef dispatch_mach_trailer_t
109 | * Trailer type of mach message received by dispatch mach channels
110 | */
111 |
112 | typedef mach_msg_context_trailer_t dispatch_mach_trailer_t;
113 |
114 | /*!
115 | * @constant DISPATCH_MACH_RECEIVE_MAX_INLINE_MESSAGE_SIZE
116 | * Maximum size of a message that can be received inline by a dispatch mach
117 | * channel, reception of larger messages requires an extra roundtrip through
118 | * the kernel.
119 | */
120 |
121 | #define DISPATCH_MACH_RECEIVE_MAX_INLINE_MESSAGE_SIZE \
122 | (0x4000 - sizeof(dispatch_mach_trailer_t))
123 |
124 | /*!
125 | * @typedef dispatch_mach_msg_t
126 | * A dispatch mach message encapsulates messages received or sent with dispatch
127 | * mach channels.
128 | */
129 | DISPATCH_DECL(dispatch_mach_msg);
130 |
131 | /*!
132 | * @typedef dispatch_mach_msg_destructor_t
133 | * Dispatch mach message object destructors.
134 | *
135 | * @const DISPATCH_MACH_MSG_DESTRUCTOR_DEFAULT
136 | * Message buffer storage is internal to the object, if a buffer is supplied
137 | * during object creation, its contents are copied.
138 | *
139 | * @const DISPATCH_MACH_MSG_DESTRUCTOR_FREE
140 | * Message buffer will be deallocated with free(3).
141 | *
142 | * @const DISPATCH_MACH_MSG_DESTRUCTOR_FREE
143 | * Message buffer will be deallocated with vm_deallocate.
144 | */
145 | DISPATCH_ENUM(dispatch_mach_msg_destructor, unsigned int,
146 | DISPATCH_MACH_MSG_DESTRUCTOR_DEFAULT = 0,
147 | DISPATCH_MACH_MSG_DESTRUCTOR_FREE,
148 | DISPATCH_MACH_MSG_DESTRUCTOR_VM_DEALLOCATE,
149 | );
150 |
151 | /*!
152 | * @function dispatch_mach_msg_create
153 | * Creates a dispatch mach message object, either with a newly allocated message
154 | * buffer of given size, or from an existing message buffer that will be
155 | * deallocated with the specified destructor when the object is released.
156 | *
157 | * If a non-NULL reference to a pointer is provided in 'msg_ptr', it is filled
158 | * with the location of the (possibly newly allocated) message buffer.
159 | *
160 | * It is the responsibility of the application to ensure that it does not modify
161 | * the underlying message buffer once the dispatch mach message object is passed
162 | * to other dispatch mach API.
163 | *
164 | * @param msg The message buffer to create the message object from.
165 | * If 'destructor' is DISPATCH_MACH_MSG_DESTRUCTOR_DEFAULT,
166 | * this argument may be NULL to leave the newly allocated
167 | * message buffer zero-initialized.
168 | * @param size The size of the message buffer.
169 | * Must be >= sizeof(mach_msg_header_t)
170 | * @param destructor The destructor to use to deallocate the message buffer
171 | * when the object is released.
172 | * @param msg_ptr A pointer to a pointer variable to be filled with the
173 | * location of the (possibly newly allocated) message
174 | * buffer, or NULL.
175 | * @result A newly created dispatch mach message object.
176 | */
177 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0)
178 | DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT
179 | DISPATCH_NOTHROW
180 | dispatch_mach_msg_t
181 | dispatch_mach_msg_create(mach_msg_header_t *msg, size_t size,
182 | dispatch_mach_msg_destructor_t destructor, mach_msg_header_t **msg_ptr);
183 |
184 | /*!
185 | * @function dispatch_mach_msg_get_msg
186 | * Returns the message buffer underlying a dispatch mach message object.
187 | *
188 | * @param message The dispatch mach message object to query.
189 | * @param size_ptr A pointer to a size_t variable to be filled with the
190 | * size of the message buffer, or NULL.
191 | * @result Pointer to message buffer underlying the object.
192 | */
193 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0)
194 | DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NOTHROW
195 | mach_msg_header_t*
196 | dispatch_mach_msg_get_msg(dispatch_mach_msg_t message, size_t *size_ptr);
197 |
198 | #ifdef __BLOCKS__
199 | /*!
200 | * @typedef dispatch_mach_handler_t
201 | * Prototype of dispatch mach channel handler blocks.
202 | *
203 | * @param reason Reason the handler was invoked.
204 | * @param message Message object that was sent or received.
205 | * @param error Mach error code for the send operation.
206 | */
207 | typedef void (^dispatch_mach_handler_t)(dispatch_mach_reason_t reason,
208 | dispatch_mach_msg_t message, mach_error_t error);
209 |
210 | /*!
211 | * @function dispatch_mach_create
212 | * Create a dispatch mach channel to asynchronously receive and send mach
213 | * messages.
214 | *
215 | * The specified handler will be called with the corresponding reason parameter
216 | * for each message received and for each message that was successfully sent,
217 | * that failed to be sent, or was not sent; as well as when a barrier block
218 | * has completed, or when channel connection, reconnection or cancellation has
219 | * taken effect.
220 | *
221 | * Dispatch mach channels are created in a disconnected state, they must be
222 | * connected via dispatch_mach_connect() to begin receiving and sending
223 | * messages.
224 | *
225 | * @param label
226 | * An optional string label to attach to the channel. The string is not copied,
227 | * if it is non-NULL it must point to storage that remains valid for the
228 | * lifetime of the channel object. May be NULL.
229 | *
230 | * @param queue
231 | * The target queue of the channel, where the handler and barrier blocks will
232 | * be submitted.
233 | *
234 | * @param handler
235 | * The handler block to submit when a message has been sent or received.
236 | *
237 | * @result
238 | * The newly created dispatch mach channel.
239 | */
240 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0)
241 | DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT
242 | DISPATCH_NONNULL3 DISPATCH_NOTHROW
243 | dispatch_mach_t
244 | dispatch_mach_create(const char *label, dispatch_queue_t queue,
245 | dispatch_mach_handler_t handler);
246 | #endif
247 |
248 | /*!
249 | * @typedef dispatch_mach_handler_function_t
250 | * Prototype of dispatch mach channel handler functions.
251 | *
252 | * @param context Application-defined context parameter.
253 | * @param reason Reason the handler was invoked.
254 | * @param message Message object that was sent or received.
255 | * @param error Mach error code for the send operation.
256 | */
257 | typedef void (*dispatch_mach_handler_function_t)(void *context,
258 | dispatch_mach_reason_t reason, dispatch_mach_msg_t message,
259 | mach_error_t error);
260 |
261 | /*!
262 | * @function dispatch_mach_create_f
263 | * Create a dispatch mach channel to asynchronously receive and send mach
264 | * messages.
265 | *
266 | * The specified handler will be called with the corresponding reason parameter
267 | * for each message received and for each message that was successfully sent,
268 | * that failed to be sent, or was not sent; as well as when a barrier block
269 | * has completed, or when channel connection, reconnection or cancellation has
270 | * taken effect.
271 | *
272 | * Dispatch mach channels are created in a disconnected state, they must be
273 | * connected via dispatch_mach_connect() to begin receiving and sending
274 | * messages.
275 | *
276 | * @param label
277 | * An optional string label to attach to the channel. The string is not copied,
278 | * if it is non-NULL it must point to storage that remains valid for the
279 | * lifetime of the channel object. May be NULL.
280 | *
281 | * @param queue
282 | * The target queue of the channel, where the handler and barrier blocks will
283 | * be submitted.
284 | *
285 | * @param context
286 | * The application-defined context to pass to the handler.
287 | *
288 | * @param handler
289 | * The handler function to submit when a message has been sent or received.
290 | *
291 | * @result
292 | * The newly created dispatch mach channel.
293 | */
294 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0)
295 | DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT
296 | DISPATCH_NONNULL4 DISPATCH_NOTHROW
297 | dispatch_mach_t
298 | dispatch_mach_create_f(const char *label, dispatch_queue_t queue, void *context,
299 | dispatch_mach_handler_function_t handler);
300 |
301 | /*!
302 | * @function dispatch_mach_connect
303 | * Connect a mach channel to the specified receive and send rights.
304 | *
305 | * This function must only be called once during the lifetime of a channel, it
306 | * will initiate message reception and perform any already submitted message
307 | * sends or barrier operations.
308 | *
309 | * @param channel
310 | * The mach channel to connect.
311 | *
312 | * @param receive
313 | * The receive right to associate with the channel. May be MACH_PORT_NULL.
314 | *
315 | * @param send
316 | * The send right to associate with the channel. May be MACH_PORT_NULL.
317 | *
318 | * @param checkin
319 | * An optional message object encapsulating the initial check-in message to send
320 | * upon channel connection. The check-in message is sent immediately before the
321 | * first message submitted via dispatch_mach_send(). The message object will be
322 | * retained until the initial send operation is complete (or not peformed due
323 | * to channel cancellation or reconnection) and the channel handler has
324 | * returned. May be NULL.
325 | */
326 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0)
327 | DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NOTHROW
328 | void
329 | dispatch_mach_connect(dispatch_mach_t channel, mach_port_t receive,
330 | mach_port_t send, dispatch_mach_msg_t checkin);
331 |
332 | /*!
333 | * @function dispatch_mach_reconnect
334 | * Reconnect a mach channel to the specified send right.
335 | *
336 | * Disconnects the channel from the current send right, interrupts any pending
337 | * message sends (and returns the messages as unsent), and reconnects the
338 | * channel to a new send right.
339 | *
340 | * The application must wait for the channel handler to be invoked with
341 | * DISPATCH_MACH_DISCONNECTED before releasing the previous send right.
342 | *
343 | * @param channel
344 | * The mach channel to reconnect.
345 | *
346 | * @param send
347 | * The new send right to associate with the channel. May be MACH_PORT_NULL.
348 | *
349 | * @param checkin
350 | * An optional message object encapsulating the initial check-in message to send
351 | * upon channel reconnection. The check-in message is sent immediately before
352 | * the first message submitted via dispatch_mach_send() after this function
353 | * returns. The message object will be retained until the initial send operation
354 | * is complete (or not peformed due to channel cancellation or reconnection)
355 | * and the channel handler has returned. May be NULL.
356 | */
357 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0)
358 | DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NOTHROW
359 | void
360 | dispatch_mach_reconnect(dispatch_mach_t channel, mach_port_t send,
361 | dispatch_mach_msg_t checkin);
362 |
363 | /*!
364 | * @function dispatch_mach_cancel
365 | * Cancel a mach channel, preventing any further messages from being sent or
366 | * received.
367 | *
368 | * The application must wait for the channel handler to be invoked with
369 | * DISPATCH_MACH_DISCONNECTED before releasing the underlying send and receive
370 | * rights.
371 | *
372 | * Note: explicit cancellation of mach channels is required, no implicit
373 | * cancellation takes place on release of the last application reference
374 | * to the channel object. Failure to cancel will cause the channel and
375 | * its associated resources to be leaked.
376 | *
377 | * @param channel
378 | * The mach channel to cancel.
379 | */
380 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0)
381 | DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
382 | void
383 | dispatch_mach_cancel(dispatch_mach_t channel);
384 |
385 | /*!
386 | * @function dispatch_mach_send
387 | * Asynchronously send a message encapsulated in a dispatch mach message object
388 | * to the specified mach channel.
389 | *
390 | * Unless the message is being sent to a send-once right (as determined by the
391 | * presence of MACH_MSG_TYPE_MOVE_SEND_ONCE in the message header remote bits),
392 | * the message header remote port is set to the channel send right before the
393 | * send operation is performed.
394 | *
395 | * If the message expects a direct reply (as determined by the presence of
396 | * MACH_MSG_TYPE_MAKE_SEND_ONCE in the message header local bits) the receive
397 | * right specified in the message header local port will be monitored until a
398 | * reply message (or a send-once notification) is received, or the channel is
399 | * canceled. Hence the application must wait for the channel handler to be
400 | * invoked with a DISPATCH_MACH_DISCONNECTED message before releasing that
401 | * receive right.
402 | *
403 | * If the message send operation is attempted but the channel is canceled
404 | * before the send operation succesfully completes, the message returned to the
405 | * channel handler with DISPATCH_MACH_MESSAGE_NOT_SENT may be the result of a
406 | * pseudo-receive operation. If the message expected a direct reply, the
407 | * receive right originally specified in the message header local port will
408 | * returned in a DISPATCH_MACH_DISCONNECTED message.
409 | *
410 | * @param channel
411 | * The mach channel to which to send the message.
412 | *
413 | * @param message
414 | * The message object encapsulating the message to send. The object will be
415 | * retained until the send operation is complete and the channel handler has
416 | * returned. The storage underlying the message object may be modified by the
417 | * send operation.
418 | *
419 | * @param options
420 | * Additional send options to pass to mach_msg() when performing the send
421 | * operation.
422 | */
423 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0)
424 | DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NONNULL2 DISPATCH_NOTHROW
425 | void
426 | dispatch_mach_send(dispatch_mach_t channel, dispatch_mach_msg_t message,
427 | mach_msg_option_t options);
428 |
429 | #ifdef __BLOCKS__
430 | /*!
431 | * @function dispatch_mach_send_barrier
432 | * Submit a send barrier to the specified mach channel. Messages submitted to
433 | * the channel before the barrier will be sent before the barrier block is
434 | * executed, and messages submitted to the channel after the barrier will only
435 | * be sent once the barrier block has completed and the channel handler
436 | * invocation for the barrier has returned.
437 | *
438 | * @param channel
439 | * The mach channel to which to submit the barrier.
440 | *
441 | * @param barrier
442 | * The barrier block to submit to the channel target queue.
443 | */
444 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0)
445 | DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
446 | void
447 | dispatch_mach_send_barrier(dispatch_mach_t channel, dispatch_block_t barrier);
448 | #endif
449 |
450 | /*!
451 | * @function dispatch_mach_send_barrier_f
452 | * Submit a send barrier to the specified mach channel. Messages submitted to
453 | * the channel before the barrier will be sent before the barrier block is
454 | * executed, and messages submitted to the channel after the barrier will only
455 | * be sent once the barrier block has completed and the channel handler
456 | * invocation for the barrier has returned.
457 | *
458 | * @param channel
459 | * The mach channel to which to submit the barrier.
460 | *
461 | * @param context
462 | * The application-defined context parameter to pass to the function.
463 | *
464 | * @param barrier
465 | * The barrier function to submit to the channel target queue.
466 | */
467 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0)
468 | DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NONNULL3 DISPATCH_NOTHROW
469 | void
470 | dispatch_mach_send_barrier_f(dispatch_mach_t channel, void *context,
471 | dispatch_function_t barrier);
472 |
473 | #ifdef __BLOCKS__
474 | /*!
475 | * @function dispatch_mach_receive_barrier
476 | * Submit a receive barrier to the specified mach channel. Channel handlers for
477 | * messages received by the channel after the receive barrier has been
478 | * submitted will only be invoked once the barrier block has completed and the
479 | * channel handler invocation for the barrier has returned.
480 | *
481 | * @param channel
482 | * The mach channel to which to submit the receive barrier.
483 | *
484 | * @param barrier
485 | * The barrier block to submit to the channel target queue.
486 | */
487 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0)
488 | DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
489 | void
490 | dispatch_mach_receive_barrier(dispatch_mach_t channel,
491 | dispatch_block_t barrier);
492 | #endif
493 |
494 | /*!
495 | * @function dispatch_mach_receive_barrier_f
496 | * Submit a receive barrier to the specified mach channel. Channel handlers for
497 | * messages received by the channel after the receive barrier has been
498 | * submitted will only be invoked once the barrier block has completed and the
499 | * channel handler invocation for the barrier has returned.
500 | *
501 | * @param channel
502 | * The mach channel to which to submit the receive barrier.
503 | *
504 | * @param context
505 | * The application-defined context parameter to pass to the function.
506 | *
507 | * @param barrier
508 | * The barrier function to submit to the channel target queue.
509 | */
510 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0)
511 | DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NONNULL3 DISPATCH_NOTHROW
512 | void
513 | dispatch_mach_receive_barrier_f(dispatch_mach_t channel, void *context,
514 | dispatch_function_t barrier);
515 |
516 | /*!
517 | * @function dispatch_mach_get_checkin_port
518 | * Returns the port specified in the message header remote port of the check-in
519 | * message passed to the most recent invocation of dispatch_mach_connect() or
520 | * dispatch_mach_reconnect() for the provided mach channel (irrespective of the
521 | * completion of the (re)connect or check-in operations in question).
522 | *
523 | * Returns MACH_PORT_NULL if dispatch_mach_connect() has not yet been called or
524 | * if the most recently specified check-in message was NULL, and MACH_PORT_DEAD
525 | * if the channel has been canceled.
526 | *
527 | * It is the responsibility of the application to ensure that the port
528 | * specified in a check-in message remains valid at the time this function is
529 | * called.
530 | *
531 | * @param channel
532 | * The mach channel to query.
533 | *
534 | * @result
535 | * The most recently specified check-in port for the channel.
536 | */
537 | __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_6_0)
538 | DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
539 | mach_port_t
540 | dispatch_mach_get_checkin_port(dispatch_mach_t channel);
541 |
542 | #endif // DISPATCH_MACH_SPI
543 |
544 | __END_DECLS
545 |
546 | #endif
--------------------------------------------------------------------------------
/Tweak.x:
--------------------------------------------------------------------------------
1 | #include
2 | #undef __IOS_PROHIBITED
3 | #define __IOS_PROHIBITED
4 |
5 | #include
6 |
7 | #define LIGHTMESSAGING_USE_ROCKETBOOTSTRAP 0
8 | #define LIGHTMESSAGING_TIMEOUT 300
9 | #import "LightMessaging/LightMessaging.h"
10 | #import "log.h"
11 | #import "unfair_lock.h"
12 |
13 | #import "rocketbootstrap_internal.h"
14 |
15 | #ifndef __APPLE_API_PRIVATE
16 | #define __APPLE_API_PRIVATE
17 | #include "sandbox.h"
18 | #undef __APPLE_API_PRIVATE
19 | #else
20 | #include "sandbox.h"
21 | #endif
22 |
23 | #import
24 | #import
25 | #import
26 | //#import
27 | #import
28 | #import
29 | #import
30 | #import
31 | #define __DISPATCH_INDIRECT__
32 | #define DISPATCH_MACH_SPI 1
33 | #import
34 |
35 | extern int *_NSGetArgc(void);
36 | extern const char ***_NSGetArgv(void);
37 |
38 | #define kUserAppsPath "/var/mobile/Applications/"
39 | #define kSystemAppsPath "/Applications/"
40 |
41 | static BOOL isDaemon;
42 |
43 | static BOOL fill_redirected_name(char new_name[BOOTSTRAP_MAX_NAME_LEN], const name_t old_name) {
44 | size_t length = strlen(old_name);
45 | if (length > 128 - 8) {
46 | return NO;
47 | }
48 | memcpy(new_name, "cy:rbs:", 7);
49 | memcpy(new_name + 7, old_name, length + 1);
50 | return YES;
51 | }
52 |
53 | static kern_return_t rocketbootstrap_look_up_with_timeout(mach_port_t bp, const name_t service_name, mach_port_t *sp, mach_msg_timeout_t timeout)
54 | {
55 | #ifdef DEBUG
56 | NSLog(@"RocketBootstrap: rocketbootstrap_look_up(%llu, %s, %p)", (unsigned long long)bp, service_name, sp);
57 | #endif
58 | if (rocketbootstrap_uses_name_redirection()) {
59 | char redirected_name[BOOTSTRAP_MAX_NAME_LEN];
60 | if (!fill_redirected_name(redirected_name, service_name)) {
61 | return 1;
62 | }
63 | kern_return_t result = bootstrap_look_up(bp, redirected_name, sp);
64 | if (result == 0) {
65 | return 0;
66 | }
67 | }
68 | if (rocketbootstrap_is_passthrough() || isDaemon) {
69 | if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_5_0) {
70 | int sandbox_result = sandbox_check(getpid(), "mach-lookup", SANDBOX_FILTER_LOCAL_NAME | SANDBOX_CHECK_NO_REPORT, service_name);
71 | if (sandbox_result) {
72 | return sandbox_result;
73 | }
74 | }
75 | return bootstrap_look_up(bp, service_name, sp);
76 | }
77 | // Compatibility mode for Flex, limits it to only the processes in rbs 1.0.1 and earlier
78 | if (strcmp(service_name, "FLMessagingCenterSpringboard") == 0) {
79 | const char **argv = *_NSGetArgv();
80 | size_t arg0len = strlen(argv[0]);
81 | bool allowed = false;
82 | if ((arg0len > sizeof(kUserAppsPath)) && (memcmp(argv[0], kUserAppsPath, sizeof(kUserAppsPath) - 1) == 0))
83 | allowed = true;
84 | if ((arg0len > sizeof(kSystemAppsPath)) && (memcmp(argv[0], kSystemAppsPath, sizeof(kSystemAppsPath) - 1) == 0))
85 | allowed = true;
86 | if (!allowed)
87 | return 1;
88 | }
89 | // Ask our service running inside of the com.apple.ReportCrash.SimulateCrash job
90 | mach_port_t servicesPort = MACH_PORT_NULL;
91 | kern_return_t err = bootstrap_look_up(bp, "com.apple.ReportCrash.SimulateCrash", &servicesPort);
92 | if (err) {
93 | #ifdef DEBUG
94 | NSLog(@"RocketBootstrap: = %lld (failed to lookup com.apple.ReportCrash.SimulateCrash)", (unsigned long long)err);
95 | #endif
96 | return err;
97 | }
98 | mach_port_t selfTask = mach_task_self();
99 | // Create a reply port
100 | mach_port_name_t replyPort = MACH_PORT_NULL;
101 | err = mach_port_allocate(selfTask, MACH_PORT_RIGHT_RECEIVE, &replyPort);
102 | if (err) {
103 | #ifdef DEBUG
104 | NSLog(@"RocketBootstrap: = %lld (failed to allocate port)", (unsigned long long)err);
105 | #endif
106 | mach_port_deallocate(selfTask, servicesPort);
107 | return err;
108 | }
109 | // Send message
110 | size_t service_name_size = strlen(service_name);
111 | size_t size = (sizeof(_rocketbootstrap_lookup_query_t) + service_name_size + 3) & ~3;
112 | if (size < sizeof(_rocketbootstrap_lookup_response_t)) {
113 | size = sizeof(_rocketbootstrap_lookup_response_t);
114 | }
115 | char buffer[size];
116 | _rocketbootstrap_lookup_query_t *message = (_rocketbootstrap_lookup_query_t *)&buffer[0];
117 | memset(message, 0, sizeof(_rocketbootstrap_lookup_response_t));
118 | message->head.msgh_id = ROCKETBOOTSTRAP_LOOKUP_ID;
119 | message->head.msgh_size = size;
120 | message->head.msgh_remote_port = servicesPort;
121 | message->head.msgh_local_port = replyPort;
122 | message->head.msgh_reserved = 0;
123 | message->head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
124 | message->name_length = service_name_size;
125 | memcpy(&message->name[0], service_name, service_name_size);
126 | mach_msg_option_t options = MACH_SEND_MSG | MACH_RCV_MSG;
127 | if (timeout == 0) {
128 | timeout = MACH_MSG_TIMEOUT_NONE;
129 | } else {
130 | options |= MACH_SEND_TIMEOUT | MACH_RCV_TIMEOUT;
131 | }
132 | err = mach_msg(&message->head, options, size, size, replyPort, timeout, MACH_PORT_NULL);
133 | // Parse response
134 | if (!err) {
135 | _rocketbootstrap_lookup_response_t *response = (_rocketbootstrap_lookup_response_t *)message;
136 | if (response->body.msgh_descriptor_count) {
137 | *sp = response->response_port.name;
138 | #ifdef DEBUG
139 | NSLog(@"RocketBootstrap: = 0 (success)");
140 | #endif
141 | } else {
142 | err = 1;
143 | #ifdef DEBUG
144 | NSLog(@"RocketBootstrap: = 1 (disallowed)");
145 | #endif
146 | }
147 | }
148 | // Cleanup
149 | mach_port_deallocate(selfTask, servicesPort);
150 | mach_port_deallocate(selfTask, replyPort);
151 | return err;
152 | }
153 |
154 | kern_return_t rocketbootstrap_look_up(mach_port_t bp, const name_t service_name, mach_port_t *sp)
155 | {
156 | return rocketbootstrap_look_up_with_timeout(bp, service_name, sp, LIGHTMESSAGING_TIMEOUT);
157 | }
158 |
159 | static NSMutableSet *allowedNames;
160 | static unfair_lock namesLock;
161 |
162 | static void daemon_restarted_callback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
163 | {
164 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
165 | unfair_lock_lock(&namesLock);
166 | NSSet *allNames = [allowedNames copy];
167 | unfair_lock_unlock(&namesLock);
168 | for (NSString *name in allNames) {
169 | const char *service_name = [name UTF8String];
170 | LMConnectionSendOneWay(&connection, 0, service_name, strlen(service_name));
171 | }
172 | [allNames release];
173 | [pool drain];
174 | }
175 |
176 | kern_return_t rocketbootstrap_unlock(const name_t service_name)
177 | {
178 | #ifdef DEBUG
179 | NSLog(@"RocketBootstrap: rocketbootstrap_unlock(%s)", service_name);
180 | #endif
181 | if (rocketbootstrap_is_passthrough())
182 | return 0;
183 | if (rocketbootstrap_uses_name_redirection()) {
184 | char redirected_name[BOOTSTRAP_MAX_NAME_LEN];
185 | if (!fill_redirected_name(redirected_name, service_name)) {
186 | return 1;
187 | }
188 | mach_port_t bootstrap = MACH_PORT_NULL;
189 | task_get_bootstrap_port(mach_task_self(), &bootstrap);
190 | mach_port_t service;
191 | kern_return_t err = bootstrap_look_up(bootstrap, service_name, &service);
192 | if (err != 0) {
193 | // If the current process is permitted to register for this port, assume it's about to
194 | int sandbox_result = sandbox_check(getpid(), "mach-register", SANDBOX_FILTER_LOCAL_NAME | SANDBOX_CHECK_NO_REPORT, service_name);
195 | if (sandbox_result) {
196 | return sandbox_result;
197 | }
198 | char *copied_service_name = strdup(service_name);
199 | CFRunLoopRef runLoop = CFRunLoopGetCurrent();
200 | CFRunLoopPerformBlock(runLoop, kCFRunLoopCommonModes, ^{
201 | mach_port_t bootstrap = MACH_PORT_NULL;
202 | task_get_bootstrap_port(mach_task_self(), &bootstrap);
203 | mach_port_t service;
204 | kern_return_t err = bootstrap_look_up(bootstrap, copied_service_name, &service);
205 | if (err == 0) {
206 | char redirected_name[BOOTSTRAP_MAX_NAME_LEN];
207 | fill_redirected_name(redirected_name, copied_service_name);
208 | err = bootstrap_register(bootstrap, redirected_name, service);
209 | if (err != 0) {
210 | mach_port_deallocate(mach_task_self(), service);
211 | }
212 | }
213 | free(copied_service_name);
214 | });
215 | CFRunLoopWakeUp(runLoop);
216 | return 0;
217 | } else {
218 | err = bootstrap_register(bootstrap, redirected_name, service);
219 | if (err != 0) {
220 | mach_port_deallocate(mach_task_self(), service);
221 | return err;
222 | }
223 | }
224 | }
225 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
226 | NSString *serviceNameString = [NSString stringWithUTF8String:service_name];
227 | unfair_lock_lock(&namesLock);
228 | BOOL containedName;
229 | if (!allowedNames) {
230 | allowedNames = [[NSMutableSet alloc] init];
231 | [allowedNames addObject:serviceNameString];
232 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), &daemon_restarted_callback, daemon_restarted_callback, CFSTR("com.rpetrich.rocketd.started"), NULL, CFNotificationSuspensionBehaviorCoalesce);
233 | containedName = NO;
234 | } else {
235 | containedName = [allowedNames containsObject:serviceNameString];
236 | if (!containedName) {
237 | [allowedNames addObject:serviceNameString];
238 | }
239 | }
240 | unfair_lock_unlock(&namesLock);
241 | [pool drain];
242 | if (containedName) {
243 | return 0;
244 | }
245 | // Ask rocketd to unlock it for us
246 | int sandbox_result = sandbox_check(getpid(), "mach-lookup", SANDBOX_FILTER_LOCAL_NAME | SANDBOX_CHECK_NO_REPORT, kRocketBootstrapUnlockService);
247 | if (sandbox_result) {
248 | return sandbox_result;
249 | }
250 | return LMConnectionSendOneWay(&connection, 0, service_name, strlen(service_name));
251 | }
252 |
253 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
254 | kern_return_t rocketbootstrap_register(mach_port_t bp, name_t service_name, mach_port_t sp)
255 | {
256 | if (rocketbootstrap_uses_name_redirection()) {
257 | char redirected_name[BOOTSTRAP_MAX_NAME_LEN];
258 | if (!fill_redirected_name(redirected_name, service_name)) {
259 | return 1;
260 | }
261 | return bootstrap_register(bp, redirected_name, sp);
262 | }
263 | kern_return_t err = rocketbootstrap_unlock(service_name);
264 | if (err)
265 | return err;
266 | return bootstrap_register(bp, service_name, sp);
267 | }
268 | #pragma GCC diagnostic warning "-Wdeprecated-declarations"
269 |
270 | static kern_return_t handle_bootstrap_lookup_msg(mach_msg_header_t *request)
271 | {
272 | _rocketbootstrap_lookup_query_t *lookup_message = (_rocketbootstrap_lookup_query_t *)request;
273 | // Extract service name
274 | size_t length = request->msgh_size - offsetof(_rocketbootstrap_lookup_query_t, name);
275 | if (lookup_message->name_length <= length) {
276 | length = lookup_message->name_length;
277 | }
278 | #ifdef DEBUG
279 | NSLog(@"RocketBootstrap: handle_bootstrap_lookup_msg(%.*s)", (int)length, &lookup_message->name[0]);
280 | #endif
281 | // Ask rocketd if it's unlocked
282 | LMResponseBuffer buffer;
283 | if (LMConnectionSendTwoWay(&connection, 1, &lookup_message->name[0], length, &buffer))
284 | return 1;
285 | BOOL nameIsAllowed = LMResponseConsumeInteger(&buffer) != 0;
286 | // Lookup service port
287 | mach_port_t servicePort = MACH_PORT_NULL;
288 | mach_port_t selfTask = mach_task_self();
289 | kern_return_t err;
290 | if (nameIsAllowed) {
291 | mach_port_t bootstrap = MACH_PORT_NULL;
292 | err = task_get_bootstrap_port(selfTask, &bootstrap);
293 | if (!err) {
294 | char *buffer = malloc(length + 1);
295 | if (buffer) {
296 | memcpy(buffer, lookup_message->name, length);
297 | buffer[length] = '\0';
298 | err = bootstrap_look_up(bootstrap, buffer, &servicePort);
299 | free(buffer);
300 | }
301 | }
302 | }
303 | // Generate response
304 | _rocketbootstrap_lookup_response_t response;
305 | response.head.msgh_id = 0;
306 | response.head.msgh_size = (sizeof(_rocketbootstrap_lookup_response_t) + 3) & ~3;
307 | response.head.msgh_remote_port = request->msgh_remote_port;
308 | response.head.msgh_local_port = MACH_PORT_NULL;
309 | response.head.msgh_reserved = 0;
310 | response.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0);
311 | if (servicePort != MACH_PORT_NULL) {
312 | response.head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
313 | response.body.msgh_descriptor_count = 1;
314 | response.response_port.name = servicePort;
315 | response.response_port.disposition = MACH_MSG_TYPE_COPY_SEND;
316 | response.response_port.type = MACH_MSG_PORT_DESCRIPTOR;
317 | } else {
318 | response.body.msgh_descriptor_count = 0;
319 | }
320 | // Send response
321 | err = mach_msg(&response.head, MACH_SEND_MSG, response.head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
322 | if (err) {
323 | if (servicePort != MACH_PORT_NULL) {
324 | mach_port_mod_refs(selfTask, servicePort, MACH_PORT_RIGHT_SEND, -1);
325 | }
326 | }
327 | return err;
328 | }
329 |
330 | mach_msg_return_t mach_msg_server_once(boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *), mach_msg_size_t max_size, mach_port_t rcv_name, mach_msg_options_t options);
331 |
332 | static mach_msg_return_t (*_mach_msg_server_once)(boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *), mach_msg_size_t max_size, mach_port_t rcv_name, mach_msg_options_t options);
333 |
334 | static unfair_lock server_once_lock;
335 | static boolean_t (*server_once_demux_orig)(mach_msg_header_t *, mach_msg_header_t *);
336 | static bool continue_server_once;
337 |
338 | static boolean_t new_demux(mach_msg_header_t *request, mach_msg_header_t *reply)
339 | {
340 | #ifdef DEBUG
341 | NSLog(@"RocketBootstrap: new_demux(%lld)", (long long)request->msgh_id);
342 | #endif
343 | // Highjack ROCKETBOOTSTRAP_LOOKUP_ID from the com.apple.ReportCrash.SimulateCrash demuxer
344 | if (request->msgh_id == ROCKETBOOTSTRAP_LOOKUP_ID) {
345 | continue_server_once = true;
346 | kern_return_t err = handle_bootstrap_lookup_msg(request);
347 | if (err) {
348 | mach_port_mod_refs(mach_task_self(), reply->msgh_remote_port, MACH_PORT_RIGHT_SEND_ONCE, -1);
349 | }
350 | return true;
351 | }
352 | return server_once_demux_orig(request, reply);
353 | }
354 |
355 | static mach_msg_return_t $mach_msg_server_once(boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *), mach_msg_size_t max_size, mach_port_t rcv_name, mach_msg_options_t options)
356 | {
357 | #ifdef DEBUG
358 | NSLog(@"RocketBootstrap: mach_msg_server_once(%p, %llu, %llu, 0x%llx)", demux, (unsigned long long)max_size, (unsigned long long)rcv_name, (long long)options);
359 | #endif
360 | // Highjack com.apple.ReportCrash.SimulateCrash's use of mach_msg_server_once
361 | unfair_lock_lock(&server_once_lock);
362 | if (!server_once_demux_orig) {
363 | server_once_demux_orig = demux;
364 | demux = new_demux;
365 | } else if (server_once_demux_orig == demux) {
366 | demux = new_demux;
367 | } else {
368 | unfair_lock_unlock(&server_once_lock);
369 | mach_msg_return_t result = _mach_msg_server_once(demux, max_size, rcv_name, options);
370 | return result;
371 | }
372 | unfair_lock_unlock(&server_once_lock);
373 | mach_msg_return_t result;
374 | do {
375 | continue_server_once = false;
376 | result = _mach_msg_server_once(demux, max_size, rcv_name, options);
377 | } while (continue_server_once);
378 | return result;
379 | }
380 |
381 | #ifdef __clang__
382 |
383 | static void *interceptedConnection;
384 |
385 | static void *(*_xpc_connection_create_mach_service)(const char *name, dispatch_queue_t targetq, uint64_t flags);
386 | static void *$xpc_connection_create_mach_service(const char *name, dispatch_queue_t targetq, uint64_t flags)
387 | {
388 | #ifdef DEBUG
389 | NSLog(@"RocketBootstrap: xpc_connection_create_mach_service(%s, %p, %lld)", name, targetq, (unsigned long long)flags);
390 | #endif
391 | if (name && strcmp(name, "com.apple.ReportCrash.SimulateCrash") == 0) {
392 | void *result = _xpc_connection_create_mach_service(name, targetq, flags);
393 | interceptedConnection = result;
394 | return result;
395 | }
396 | return _xpc_connection_create_mach_service(name, targetq, flags);
397 | }
398 |
399 | static void (*__xpc_connection_mach_event)(void *context, dispatch_mach_reason_t reason, dispatch_mach_msg_t message, mach_error_t error);
400 | static void $_xpc_connection_mach_event(void *context, dispatch_mach_reason_t reason, dispatch_mach_msg_t message, mach_error_t error)
401 | {
402 | #ifdef DEBUG
403 | NSLog(@"RocketBootstrap: _xpc_connection_mach_event(%p, %lu, %p, 0x%x)", context, reason, message, error);
404 | #endif
405 | // Highjack ROCKETBOOTSTRAP_LOOKUP_ID from the com.apple.ReportCrash.SimulateCrash XPC service
406 | if ((reason == DISPATCH_MACH_MESSAGE_RECEIVED) && (context == interceptedConnection)) {
407 | size_t size;
408 | mach_msg_header_t *header = dispatch_mach_msg_get_msg(message, &size);
409 | if (header->msgh_id == ROCKETBOOTSTRAP_LOOKUP_ID) {
410 | handle_bootstrap_lookup_msg(header);
411 | return;
412 | }
413 | }
414 | return __xpc_connection_mach_event(context, reason, message, error);
415 | }
416 |
417 | #endif
418 |
419 | static pid_t pid_of_process(const char *process_name)
420 | {
421 | int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
422 | size_t miblen = 4;
423 |
424 | size_t size;
425 | int st = sysctl(mib, miblen, NULL, &size, NULL, 0);
426 |
427 | struct kinfo_proc * process = NULL;
428 | struct kinfo_proc * newprocess = NULL;
429 |
430 | do {
431 | if (size == 0){
432 | st = sysctl(mib, miblen, NULL, &size, NULL, 0);
433 | }
434 |
435 | size += size / 10;
436 | newprocess = (struct kinfo_proc *)realloc(process, size);
437 |
438 | if (!newprocess) {
439 | if (process) {
440 | free(process);
441 | }
442 | return 0;
443 | }
444 |
445 | process = newprocess;
446 | st = sysctl(mib, miblen, process, &size, NULL, 0);
447 |
448 | } while (st == -1 && errno == ENOMEM);
449 |
450 | if (st == 0) {
451 | if (size % sizeof(struct kinfo_proc) == 0) {
452 | int nprocess = size / sizeof(struct kinfo_proc);
453 | if (nprocess) {
454 | for (int i = nprocess - 1; i >= 0; i--) {
455 | if (strcmp(process[i].kp_proc.p_comm, process_name) == 0) {
456 | pid_t result = process[i].kp_proc.p_pid;
457 | free(process);
458 | return result;
459 | }
460 | }
461 | }
462 | }
463 | }
464 |
465 | free(process);
466 | return 0;
467 | }
468 |
469 | static int daemon_die_queue;
470 | static CFFileDescriptorRef daemon_die_fd;
471 | static CFRunLoopSourceRef daemon_die_source;
472 |
473 | static void process_terminate_callback(CFFileDescriptorRef fd, CFOptionFlags callBackTypes, void *info);
474 |
475 | static void observe_rocketd(void)
476 | {
477 | // Force the daemon to load
478 | mach_port_t bootstrap = MACH_PORT_NULL;
479 | mach_port_t self = mach_task_self();
480 | task_get_bootstrap_port(self, &bootstrap);
481 | mach_port_t servicesPort = MACH_PORT_NULL;
482 | kern_return_t err = bootstrap_look_up(bootstrap, "com.rpetrich.rocketbootstrapd", &servicesPort);
483 | if (err) {
484 | #if __clang__
485 | #pragma clang diagnostic push
486 | #pragma clang diagnostic ignored "-Wavailability"
487 | #endif
488 | pid_t pid;
489 | char *const argv[] = { "/usr/libexec/_rocketd_reenable", NULL };
490 | if (posix_spawn(&pid, "/usr/libexec/_rocketd_reenable", NULL, NULL, argv, NULL) == 0) {
491 | waitpid(pid, NULL, 0);
492 | }
493 | #if __clang__
494 | #pragma clang diagnostic pop
495 | #endif
496 | err = bootstrap_look_up(bootstrap, "com.rpetrich.rocketbootstrapd", &servicesPort);
497 | }
498 | if (err) {
499 | #ifdef DEBUG
500 | NSLog(@"RocketBootstrap: failed to launch rocketd!");
501 | #endif
502 | } else {
503 | mach_port_name_t replyPort = MACH_PORT_NULL;
504 | err = mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, &replyPort);
505 | if (err == 0) {
506 | LMResponseBuffer buffer;
507 | uint32_t size = LMBufferSizeForLength(0);
508 | memset(&buffer.message, 0, sizeof(LMMessage));
509 | buffer.message.head.msgh_id = 2;
510 | buffer.message.head.msgh_size = size;
511 | buffer.message.head.msgh_local_port = replyPort;
512 | buffer.message.head.msgh_reserved = 0;
513 | buffer.message.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
514 | buffer.message.head.msgh_remote_port = servicesPort;
515 | buffer.message.body.msgh_descriptor_count = 0;
516 | buffer.message.data.in_line.length = 0;
517 | err = mach_msg(&buffer.message.head, MACH_SEND_MSG | MACH_RCV_MSG | _LIGHTMESSAGING_TIMEOUT_FLAGS, size, sizeof(LMResponseBuffer), replyPort, LIGHTMESSAGING_TIMEOUT, MACH_PORT_NULL);
518 | if (err) {
519 | }
520 | // Cleanup
521 | mach_port_mod_refs(self, replyPort, MACH_PORT_RIGHT_RECEIVE, -1);
522 | }
523 | mach_port_mod_refs(self, servicesPort, MACH_PORT_RIGHT_SEND, -1);
524 | }
525 | // Find it
526 | pid_t pid = pid_of_process("rocketd");
527 | if (pid) {
528 | #ifdef DEBUG
529 | NSLog(@"RocketBootstrap: rocketd found: %d", pid);
530 | #endif
531 | daemon_die_queue = kqueue();
532 | struct kevent changes;
533 | EV_SET(&changes, pid, EVFILT_PROC, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, NULL);
534 | (void)kevent(daemon_die_queue, &changes, 1, &changes, 1, NULL);
535 | daemon_die_fd = CFFileDescriptorCreate(NULL, daemon_die_queue, true, process_terminate_callback, NULL);
536 | daemon_die_source = CFFileDescriptorCreateRunLoopSource(NULL, daemon_die_fd, 0);
537 | CFRunLoopAddSource(CFRunLoopGetCurrent(), daemon_die_source, kCFRunLoopDefaultMode);
538 | CFFileDescriptorEnableCallBacks(daemon_die_fd, kCFFileDescriptorReadCallBack);
539 | } else {
540 | NSLog(@"RocketBootstrap: unable to find rocketd!");
541 | }
542 | }
543 |
544 | static void process_terminate_callback(CFFileDescriptorRef fd, CFOptionFlags callBackTypes, void *info)
545 | {
546 | struct kevent event;
547 | (void)kevent(daemon_die_queue, NULL, 0, &event, 1, NULL);
548 | NSLog(@"RocketBootstrap: rocketd terminated: %d, relaunching", (int)(pid_t)event.ident);
549 | // Cleanup
550 | CFRunLoopRemoveSource(CFRunLoopGetCurrent(), daemon_die_source, kCFRunLoopDefaultMode);
551 | CFRelease(daemon_die_source);
552 | CFRelease(daemon_die_fd);
553 | close(daemon_die_queue);
554 | observe_rocketd();
555 | }
556 |
557 | static void SanityCheckNotificationCallback(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
558 | {
559 | }
560 |
561 | %ctor
562 | {
563 | %init();
564 | // Attach rockets when in the com.apple.ReportCrash.SimulateCrash job
565 | // (can't check in using the launchd APIs because it hates more than one checkin; this will do)
566 | const char **_argv = *_NSGetArgv();
567 | if (strcmp(_argv[0], "/System/Library/CoreServices/ReportCrash") == 0 && _argv[1]) {
568 | if (strcmp(_argv[1], "-f") == 0) {
569 | isDaemon = YES;
570 | #ifdef DEBUG
571 | NSLog(@"RocketBootstrap: Initializing ReportCrash using mach_msg_server");
572 | #endif
573 | MSHookFunction(mach_msg_server_once, $mach_msg_server_once, (void **)&_mach_msg_server_once);
574 | #ifdef __clang__
575 | } else if (strcmp(_argv[1], "com.apple.ReportCrash.SimulateCrash") == 0) {
576 | isDaemon = YES;
577 | #ifdef DEBUG
578 | NSLog(@"RocketBootstrap: Initializing ReportCrash using XPC");
579 | #endif
580 | MSImageRef libxpc = MSGetImageByName("/usr/lib/system/libxpc.dylib");
581 | if (libxpc) {
582 | void *xpc_connection_create_mach_service = MSFindSymbol(libxpc, "_xpc_connection_create_mach_service");
583 | if (xpc_connection_create_mach_service) {
584 | MSHookFunction(xpc_connection_create_mach_service, $xpc_connection_create_mach_service, (void **)&_xpc_connection_create_mach_service);
585 | } else {
586 | #ifdef DEBUG
587 | NSLog(@"RocketBootstrap: Could not find xpc_connection_create_mach_service symbol!");
588 | #endif
589 | }
590 | void *_xpc_connection_mach_event = MSFindSymbol(libxpc, "__xpc_connection_mach_event");
591 | if (_xpc_connection_mach_event) {
592 | MSHookFunction(_xpc_connection_mach_event, $_xpc_connection_mach_event, (void **)&__xpc_connection_mach_event);
593 | } else {
594 | #ifdef DEBUG
595 | NSLog(@"RocketBootstrap: Could not find _xpc_connection_mach_event symbol!");
596 | #endif
597 | }
598 | } else {
599 | #ifdef DEBUG
600 | NSLog(@"RocketBootstrap: Could not find libxpc.dylib image!");
601 | #endif
602 | }
603 | #endif
604 | }
605 | } else if (strcmp(argv[0], "/System/Library/CoreServices/SpringBoard.app/SpringBoard") == 0) {
606 | #ifdef DEBUG
607 | NSLog(@"RocketBootstrap: Initializing SpringBoard");
608 | #endif
609 | if (kCFCoreFoundationVersionNumber < 847.20) {
610 | return;
611 | }
612 | // Sanity check on the SimulateCrash service
613 | mach_port_t bootstrap = MACH_PORT_NULL;
614 | mach_port_t self = mach_task_self();
615 | task_get_bootstrap_port(self, &bootstrap);
616 | mach_port_t servicesPort = MACH_PORT_NULL;
617 | kern_return_t err = bootstrap_look_up(bootstrap, "com.apple.ReportCrash.SimulateCrash", &servicesPort);
618 | //bool has_simulate_crash;
619 | if (err) {
620 | //has_simulate_crash = false;
621 | } else {
622 | mach_port_mod_refs(self, servicesPort, MACH_PORT_RIGHT_SEND, -1);
623 | //has_simulate_crash = true;
624 | //servicesPort = MACH_PORT_NULL;
625 | //err = bootstrap_look_up(bootstrap, "com.rpetrich.rocketbootstrapd", &servicesPort);
626 | }
627 | if (err == 0) {
628 | mach_port_mod_refs(self, servicesPort, MACH_PORT_RIGHT_SEND, -1);
629 | observe_rocketd();
630 | } else {
631 | const CFTypeRef keys[] = {
632 | kCFUserNotificationAlertHeaderKey,
633 | kCFUserNotificationAlertMessageKey,
634 | kCFUserNotificationDefaultButtonTitleKey,
635 | };
636 | const CFTypeRef valuesCrash[] = {
637 | CFSTR("System files missing!"),
638 | CFSTR("RocketBootstrap has detected that your SimulateCrash crash reporting daemon is missing or disabled.\nThis daemon is required for proper operation of packages that depend on RocketBootstrap."),
639 | CFSTR("OK"),
640 | };
641 | /*const CFTypeRef valuesRocket[] = {
642 | CFSTR("System files missing!"),
643 | CFSTR("RocketBootstrap has detected that your rocketbootstrap daemon is missing or disabled.\nThis daemon is required for proper operation of packages that depend on RocketBootstrap."),
644 | CFSTR("OK"),
645 | };*/
646 | CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, /*has_simulate_crash ? (const void **)valuesRocket :*/ (const void **)valuesCrash, sizeof(keys) / sizeof(*keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
647 | SInt32 err = 0;
648 | CFUserNotificationRef notification = CFUserNotificationCreate(kCFAllocatorDefault, 0.0, kCFUserNotificationPlainAlertLevel, &err, dict);
649 | CFRunLoopSourceRef runLoopSource = CFUserNotificationCreateRunLoopSource(kCFAllocatorDefault, notification, SanityCheckNotificationCallback, 0);
650 | CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, kCFRunLoopCommonModes);
651 | CFRelease(dict);
652 | }
653 | }
654 | }
655 |
--------------------------------------------------------------------------------