aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcomex2015-07-11 18:41:10 -0400
committercomex2015-07-11 18:41:10 -0400
commitf5089d804a2697ce590e42c9858ea044bec4db36 (patch)
tree8e26066e157cbb4396cacec4d56c692532534156
parentworking on safety (diff)
downloadsubstitute-f5089d804a2697ce590e42c9858ea044bec4db36.tar.gz
progress
-rwxr-xr-xconfigure1
-rw-r--r--darwin-bootstrap/safemode-ui-hook.m93
-rw-r--r--darwin-bootstrap/substituted.m37
3 files changed, 122 insertions, 9 deletions
diff --git a/configure b/configure
index 8157eaa..b7d8335 100755
--- a/configure
+++ b/configure
@@ -217,6 +217,7 @@ if settings.enable_ios_bootstrap:
('exec', '(out)/unrestrict', ['(src)/darwin-bootstrap/unrestrict.c'], ls, [], []),
('exec', '(out)/inject-into-launchd', ['(src)/darwin-bootstrap/inject-into-launchd.c'], ls, ['-framework', 'IOKit', '-framework', 'CoreFoundation'], []),
('exec', '(out)/substituted', ['(src)/darwin-bootstrap/substituted.m'], ls, ['-lbsm', '-framework', 'Foundation', '-framework', 'CoreFoundation'], ['-fobjc-arc']),
+ ('dylib', '(out)/safemode-ui-hook.dylib', ['(src)/darwin-bootstrap/safemode-ui-hook.m'], ls, ['-framework', 'Foundation', '-framework', 'UIKit'], ['-fobjc-arc']),
]:
mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings.specialize(override_ldflags=ldf+settings.host.ldflags, override_cflags=cf+settings.host.cflags), ty, out, ins, objs=objs)
diff --git a/darwin-bootstrap/safemode-ui-hook.m b/darwin-bootstrap/safemode-ui-hook.m
new file mode 100644
index 0000000..f762c6d
--- /dev/null
+++ b/darwin-bootstrap/safemode-ui-hook.m
@@ -0,0 +1,93 @@
+#include "substitute.h"
+#include <objc/runtime.h>
+#include <notify.h>
+#include <dispatch/dispatch.h>
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/* TODO: test what happens when both are required */
+
+static bool g_did_say_in_setup_mode;
+static bool g_did_exit_safety_dance;
+
+@interface _SBApplicationController
+- (id)applicationWithBundleIdentifier:(NSString *)identifier;
+@end
+
+@interface _SBSetupManager
+- (bool)updateInSetupMode;
+- (bool)_setInSetupMode:(bool)inSetupMode;
+- (id)applicationWithBundleIdentifier:(NSString *)identifier;
+@end
+
+@interface _SpringBoard
+- (void)relaunchSpringBoard;
+@end
+
+static id (*old_setupApplication)(id, SEL);
+static id my_setupApplication(id self, SEL sel) {
+ if (g_did_say_in_setup_mode)
+ return [self applicationWithBundleIdentifier:@"com.ex.SafetyDance"];
+ return old_setupApplication(self, sel);
+}
+
+static bool (*old_updateInSetupMode)(id, SEL);
+static bool my_updateInSetupMode(id self, SEL sel) {
+ if (g_did_exit_safety_dance) {
+ g_did_say_in_setup_mode = false;
+ return old_updateInSetupMode(self, sel);
+ } else {
+ /* take priority over real setup */
+ g_did_say_in_setup_mode = true;
+ [self _setInSetupMode:true];
+ return true;
+ }
+}
+
+static bool (*old__handleSetupExited)(id, SEL, id);
+static bool my__handleSetupExited(id self, SEL sel, id app) {
+ if (g_did_say_in_setup_mode)
+ g_did_exit_safety_dance = true;
+ return old__handleSetupExited(self, sel, app);
+}
+
+__attribute__((constructor))
+static void init() {
+ #define GET(clsname) \
+ Class clsname = objc_getClass(#clsname); \
+ if (!clsname) { \
+ NSLog(@"substitute safe mode failed to find %s", #clsname); \
+ return; \
+ }
+
+ GET(SBApplicationController);
+ GET(SBSetupManager);
+ GET(SBWorkspace);
+
+ int notify_token;
+ uint32_t notify_status = notify_register_dispatch(
+ "com.ex.substitute.safemode-restart-springboard-plz",
+ &notify_token, dispatch_get_main_queue(), ^(int tok) {
+ id sb = [UIApplication sharedApplication];
+ [sb relaunchSpringBoard];
+ }
+ );
+
+ #define HOOK(cls, sel, selvar) do { \
+ int ret = substitute_hook_objc_message(cls, @selector(sel), \
+ my_##selvar, \
+ &old_##selvar, NULL); \
+ if (ret) { \
+ NSLog(@"substitute safe mode '%s' hook failed: %d", #sel, ret); \
+ return; \
+ } \
+ } while(0)
+
+ /* note: any of these might fail, leaving the previous ones hooked */
+
+ HOOK(SBApplicationController, setupApplication, setupApplication);
+ HOOK(SBWorkspace, _handleSetupExited:, _handleSetupExited);
+ HOOK(SBSetupManager, updateInSetupMode, updateInSetupMode);
+
+
+}
diff --git a/darwin-bootstrap/substituted.m b/darwin-bootstrap/substituted.m
index 5cb1b11..43654c2 100644
--- a/darwin-bootstrap/substituted.m
+++ b/darwin-bootstrap/substituted.m
@@ -9,7 +9,11 @@
* libraries into the target binary (unless actually required by loaded
* libraries). In the future it will help with hot loading. */
-static bool g_springboard_needs_safe;
+static enum {
+ NO_SAFE,
+ NEEDS_SAFE,
+ REALLY_SAFE,
+} g_springboard_needs_safe;
extern kern_return_t bootstrap_look_up3(mach_port_t bp,
const char *service_name, mach_port_t *sp, pid_t target_pid,
@@ -91,17 +95,22 @@ enum convert_filters_ret {
}
}
- bool safe_mode = false;
+ bool for_safe_mode = false;
NSNumber *safe_mode_num = [filter objectForKey:@"SafeMode"];
if (safe_mode_num) {
if ([safe_mode_num isEqual:[NSNumber numberWithBool:true]])
- safe_mode = true;
+ for_safe_mode = true;
else if (![safe_mode_num isEqual:[NSNumber numberWithBool:false]])
return INVALID;
}
- if ((safe_mode && !_is_springboard) ||
- safe_mode != g_springboard_needs_safe)
- return FAIL;
+ /* in REALLY_SAFE mode, nothing gets loaded */
+ if (for_safe_mode) {
+ if (!_is_springboard || g_springboard_needs_safe != NEEDS_SAFE)
+ return FAIL;
+ } else {
+ if (_is_springboard && g_springboard_needs_safe != NO_SAFE)
+ return FAIL;
+ }
bool any = false;
NSString *mode_str = [filter objectForKey:@"Mode"];
@@ -249,9 +258,19 @@ enum convert_filters_ret {
- (void)handleHangup {
/* this could be false because hello hasn't been sent, but in that case it
* hasn't loaded any substitute dylibs, so not our problem *whistle* */
- if (_is_springboard && !_got_bye) {
- NSLog(@"SpringBoard hung up without saying bye; using safe mode next time.");
- g_springboard_needs_safe = true;
+ if (_is_springboard) {
+ bool needs_safe = !_got_bye;
+ if (needs_safe) {
+ if (g_springboard_needs_safe) {
+ NSLog(@"SpringBoard hung up more than once without without saying bye; using Really Safe Mode (no UI) next time :(");
+ g_springboard_needs_safe = REALLY_SAFE;
+ } else {
+ NSLog(@"SpringBoard hung up without saying bye; using safe mode next time.");
+ g_springboard_needs_safe = NEEDS_SAFE;
+ }
+ } else {
+ g_springboard_needs_safe = NO_SAFE;
+ }
}
}