ios: Tighten up UIGestureEnvironment exception detection.

iOS 15.1 reordered private APIs before public APIs when looking at the
unw_get_proc_info() frame_info.start_ip, so doing a min/max within
UIGestureEnvironment would fail on devices. However, this API is always
called by UIWindow sendEvent, which is not a private API. Do the same
check, but instead look back 2 frames, and check to see if we are
within UIWindow.

Both APIs are still marked <redacted>, but the detection should still
work.

Also cleans up some tests fixtures when running in release.

Change-Id: I762615e9cb44389800cf3291af52a7568c3825d5
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3299008
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Justin Cohen <justincohen@chromium.org>
This commit is contained in:
Justin Cohen 2021-11-23 13:59:19 -05:00 committed by Crashpad LUCI CQ
parent 54f2581bf1
commit c7ce2e3ec1
2 changed files with 17 additions and 22 deletions

View File

@ -403,20 +403,22 @@ id ObjcExceptionPreprocessor(id exception) {
// internally and also has has non-sinkhole handlers. While all the
// calling methods in UIKit are marked <redacted> starting in iOS14, it's
// currently true that all callers to _UIGestureEnvironmentUpdate are within
// UIGestureEnvironment. That means a very hacky way to detect this are to
// check if the calling method IMP is within the range of all
// UIGestureEnvironment methods.
// UIWindow sendEvent -> UIGestureEnvironment. That means a very hacky way
// to detect this is to check if the calling (2x) method IMP is within the
// range of all UIWindow methods.
static constexpr const char kUIKitCorePath[] =
"/System/Library/PrivateFrameworks/UIKitCore.framework/UIKitCore";
if (ModulePathMatchesSinkhole(dl_info.dli_fname, kUIKitCorePath)) {
unw_proc_info_t caller_frame_info;
if (LoggingUnwStep(&cursor) > 0 &&
unw_get_proc_info(&cursor, &caller_frame_info) == UNW_ESUCCESS &&
LoggingUnwStep(&cursor) > 0 &&
unw_get_proc_info(&cursor, &caller_frame_info) == UNW_ESUCCESS) {
auto uigestureimp_lambda = [](IMP* max) {
auto uiwindowimp_lambda = [](IMP* max) {
IMP min = *max = bit_cast<IMP>(nullptr);
unsigned int method_count = 0;
std::unique_ptr<Method[], base::FreeDeleter> method_list(
class_copyMethodList(NSClassFromString(@"UIGestureEnvironment"),
class_copyMethodList(NSClassFromString(@"UIWindow"),
&method_count));
if (method_count > 0) {
min = *max = method_getImplementation(method_list[0]);
@ -431,15 +433,14 @@ id ObjcExceptionPreprocessor(id exception) {
return min;
};
static IMP gesture_environment_max_imp;
static IMP gesture_environment_min_imp =
uigestureimp_lambda(&gesture_environment_max_imp);
static IMP uiwindow_max_imp;
static IMP uiwindow_min_imp = uiwindowimp_lambda(&uiwindow_max_imp);
if (gesture_environment_min_imp && gesture_environment_max_imp &&
if (uiwindow_min_imp && uiwindow_max_imp &&
caller_frame_info.start_ip >=
reinterpret_cast<unw_word_t>(gesture_environment_min_imp) &&
reinterpret_cast<unw_word_t>(uiwindow_min_imp) &&
caller_frame_info.start_ip <=
reinterpret_cast<unw_word_t>(gesture_environment_max_imp)) {
reinterpret_cast<unw_word_t>(uiwindow_max_imp)) {
return HANDLE_UNCAUGHT_NSEXCEPTION(exception,
"_UIGestureEnvironmentUpdate");
}

View File

@ -85,12 +85,8 @@
- (void)testSegv {
[rootObject_ crashSegv];
#if defined(NDEBUG)
#if TARGET_OS_SIMULATOR
#if defined(NDEBUG) && TARGET_OS_SIMULATOR
[self verifyCrashReportException:SIGINT];
#else
[self verifyCrashReportException:SIGABRT];
#endif
#else
[self verifyCrashReportException:SIGHUP];
#endif
@ -117,12 +113,8 @@
- (void)testBadAccess {
[rootObject_ crashBadAccess];
#if defined(NDEBUG)
#if TARGET_OS_SIMULATOR
#if defined(NDEBUG) && TARGET_OS_SIMULATOR
[self verifyCrashReportException:SIGINT];
#else
[self verifyCrashReportException:SIGABRT];
#endif
#else
[self verifyCrashReportException:SIGHUP];
#endif
@ -221,6 +213,7 @@
XCTAssertTrue([dict[@"ver"] isEqualToString:@"42"]);
}
#if TARGET_OS_SIMULATOR
- (void)testCrashWithCrashInfoMessage {
if (@available(iOS 15.0, *)) {
// Figure out how to test this on iOS15.
@ -232,9 +225,10 @@
NSString* dyldMessage = dict[@"vector"][0];
XCTAssertTrue([dyldMessage isEqualToString:@"dyld: in dlsym()"]);
}
#endif
// TODO(justincohen): Codesign crashy_initializer.so so it can run on devices.
#if !TARGET_OS_SIMULATOR
#if TARGET_OS_SIMULATOR
- (void)testCrashWithDyldErrorString {
if (@available(iOS 15.0, *)) {
// iOS 15 uses dyld4, which doesn't use CRSetCrashLogMessage2