Title: [252054] branches/safari-608-branch

Diff

Modified: branches/safari-608-branch/Source/WebKit/ChangeLog (252053 => 252054)


--- branches/safari-608-branch/Source/WebKit/ChangeLog	2019-11-05 16:40:22 UTC (rev 252053)
+++ branches/safari-608-branch/Source/WebKit/ChangeLog	2019-11-05 16:40:27 UTC (rev 252054)
@@ -1,5 +1,39 @@
 2019-11-05  Alan Coon  <[email protected]>
 
+        Apply patch. rdar://problem/56903274
+
+    2019-11-05  Jiewen Tan  <[email protected]>
+
+            [WebAuthn] Guard against unexpected -[_WKWebAuthenticationPanel cancel]
+            https://bugs.webkit.org/show_bug.cgi?id=203830
+            <rdar://problem/56797134>
+
+            Reviewed by Brent Fulgham .
+
+            -[_WKWebAuthenticationPanel cancel] was only expected to be called on behalf of an
+            explicit user cancel from the UI. However, clients may call it in different other
+            unexpected scenarios as well. We should guard against that.
+
+            To do so, two counter ways are implemented:
+            1) AuthenticatorManager::cancelRequest is changed to invoke the pending request if there
+            is no GlobalFrameID. This case can only be reached via calling -[_WKWebAuthenticationPanel cancel]
+            before AuthenticatorManager::cancelRequest.
+            2) WebAuthenticationPanelClient::updatePanel and WebAuthenticationPanelClient::dismissPanel
+            will call delegate methods in the next run loop to prevent -[_WKWebAuthenticationPanel cancel]
+            being called in the delegates.
+
+            Covered by new API tests.
+
+            * UIProcess/WebAuthentication/AuthenticatorManager.cpp:
+            (WebKit::AuthenticatorManager::cancelRequest):
+            (WebKit::AuthenticatorManager::createService const):
+            (WebKit::AuthenticatorManager::invokePendingCompletionHandler):
+            * UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm:
+            (WebKit::WebAuthenticationPanelClient::updatePanel const):
+            (WebKit::WebAuthenticationPanelClient::dismissPanel const):
+
+2019-11-05  Alan Coon  <[email protected]>
+
         Cherry-pick r248121. rdar://problem/56903580
 
     Crash under WebProcessProxy::didBecomeUnresponsive()

Modified: branches/safari-608-branch/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp (252053 => 252054)


--- branches/safari-608-branch/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp	2019-11-05 16:40:22 UTC (rev 252053)
+++ branches/safari-608-branch/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp	2019-11-05 16:40:27 UTC (rev 252054)
@@ -165,15 +165,16 @@
     runPanel();
 }
 
-void AuthenticatorManager::cancelRequest(const WebCore::PageIdentifier& pageID, const Optional<FrameIdentifier>& frameID)
+void AuthenticatorManager::cancelRequest(const PageIdentifier& pageID, const Optional<FrameIdentifier>& frameID)
 {
     if (!m_pendingCompletionHandler)
         return;
-    ASSERT(m_pendingRequestData.frameID);
-    if (m_pendingRequestData.frameID->pageID != pageID)
-        return;
-    if (frameID && frameID != m_pendingRequestData.frameID->frameID)
-        return;
+    if (auto pendingFrameID = m_pendingRequestData.frameID) {
+        if (pendingFrameID->pageID != pageID)
+            return;
+        if (frameID && frameID != pendingFrameID->frameID)
+            return;
+    }
     invokePendingCompletionHandler(ExceptionData { NotAllowedError, "Operation timed out."_s });
     clearState();
     m_requestTimeOutTimer.stop();
@@ -184,6 +185,7 @@
 // "If the user exercises a user agent user-interface option to cancel the process,".
 void AuthenticatorManager::cancelRequest(const API::WebAuthenticationPanel& panel)
 {
+    RELEASE_ASSERT(RunLoop::isMain());
     if (!m_pendingCompletionHandler || m_pendingRequestData.panel.get() != &panel)
         return;
     resetState();
@@ -257,7 +259,7 @@
         panel->client().updatePanel(status);
 }
 
-UniqueRef<AuthenticatorTransportService> AuthenticatorManager::createService(WebCore::AuthenticatorTransport transport, AuthenticatorTransportService::Observer& observer) const
+UniqueRef<AuthenticatorTransportService> AuthenticatorManager::createService(AuthenticatorTransport transport, AuthenticatorTransportService::Observer& observer) const
 {
     return AuthenticatorTransportService::create(transport, observer);
 }
@@ -336,9 +338,9 @@
 void AuthenticatorManager::invokePendingCompletionHandler(Respond&& respond)
 {
     if (auto *panel = m_pendingRequestData.panel.get()) {
-        WTF::switchOn(respond, [&](const WebCore::PublicKeyCredentialData&) {
+        WTF::switchOn(respond, [&](const PublicKeyCredentialData&) {
             panel->client().dismissPanel(WebAuthenticationResult::Succeeded);
-        }, [&](const  WebCore::ExceptionData&) {
+        }, [&](const ExceptionData&) {
             panel->client().dismissPanel(WebAuthenticationResult::Failed);
         });
     }
@@ -345,7 +347,6 @@
     m_pendingCompletionHandler(WTFMove(respond));
 }
 
-
 void AuthenticatorManager::resetState()
 {
     m_authenticators.clear();

Modified: branches/safari-608-branch/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm (252053 => 252054)


--- branches/safari-608-branch/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm	2019-11-05 16:40:22 UTC (rev 252053)
+++ branches/safari-608-branch/Source/WebKit/UIProcess/WebAuthentication/Cocoa/WebAuthenticationPanelClient.mm	2019-11-05 16:40:27 UTC (rev 252054)
@@ -30,6 +30,7 @@
 
 #import "WebAuthenticationFlags.h"
 #import "_WKWebAuthenticationPanel.h"
+#import <wtf/RunLoop.h>
 
 namespace WebKit {
 
@@ -58,14 +59,21 @@
 
 void WebAuthenticationPanelClient::updatePanel(WebAuthenticationStatus status) const
 {
-    if (!m_delegateMethods.panelUpdateWebAuthenticationPanel)
-        return;
+    // Call delegates in the next run loop to prevent clients' reentrance that would potentially modify the state
+    // of the current run loop in unexpected ways.
+    RunLoop::main().dispatch([weakThis = makeWeakPtr(*this), this, status] {
+        if (!weakThis)
+            return;
 
-    auto delegate = m_delegate.get();
-    if (!delegate)
-        return;
+        if (!m_delegateMethods.panelUpdateWebAuthenticationPanel)
+            return;
 
-    [delegate panel:m_panel updateWebAuthenticationPanel:wkWebAuthenticationPanelUpdate(status)];
+        auto delegate = m_delegate.get();
+        if (!delegate)
+            return;
+
+        [delegate panel:m_panel updateWebAuthenticationPanel:wkWebAuthenticationPanelUpdate(status)];
+    });
 }
 
 static _WKWebAuthenticationResult wkWebAuthenticationResult(WebAuthenticationResult result)
@@ -82,14 +90,21 @@
 
 void WebAuthenticationPanelClient::dismissPanel(WebAuthenticationResult result) const
 {
-    if (!m_delegateMethods.panelDismissWebAuthenticationPanelWithResult)
-        return;
+    // Call delegates in the next run loop to prevent clients' reentrance that would potentially modify the state
+    // of the current run loop in unexpected ways.
+    RunLoop::main().dispatch([weakThis = makeWeakPtr(*this), this, result] {
+        if (!weakThis)
+            return;
 
-    auto delegate = m_delegate.get();
-    if (!delegate)
-        return;
+        if (!m_delegateMethods.panelDismissWebAuthenticationPanelWithResult)
+            return;
 
-    [delegate panel:m_panel dismissWebAuthenticationPanelWithResult:wkWebAuthenticationResult(result)];
+        auto delegate = m_delegate.get();
+        if (!delegate)
+            return;
+
+        [delegate panel:m_panel dismissWebAuthenticationPanelWithResult:wkWebAuthenticationResult(result)];
+    });
 }
 
 } // namespace WebKit

Modified: branches/safari-608-branch/Tools/ChangeLog (252053 => 252054)


--- branches/safari-608-branch/Tools/ChangeLog	2019-11-05 16:40:22 UTC (rev 252053)
+++ branches/safari-608-branch/Tools/ChangeLog	2019-11-05 16:40:27 UTC (rev 252054)
@@ -1,3 +1,20 @@
+2019-11-05  Alan Coon  <[email protected]>
+
+        Apply patch. rdar://problem/56903274
+
+    2019-11-05  Jiewen Tan  <[email protected]>
+
+            [WebAuthn] Guard against unexpected -[_WKWebAuthenticationPanel cancel]
+            https://bugs.webkit.org/show_bug.cgi?id=203830
+            <rdar://problem/56797134>
+
+            Reviewed by Brent Fulgham .
+
+            * TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm:
+            (-[TestWebAuthenticationPanelDelegate panel:updateWebAuthenticationPanel:]):
+            (-[TestWebAuthenticationPanelDelegate panel:dismissWebAuthenticationPanelWithResult:]):
+            (TestWebKitAPI::TEST):
+
 2019-11-04  Alan Coon  <[email protected]>
 
         Apply patch. rdar://problem/56864381

Modified: branches/safari-608-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm (252053 => 252054)


--- branches/safari-608-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm	2019-11-05 16:40:22 UTC (rev 252053)
+++ branches/safari-608-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/_WKWebAuthenticationPanel.mm	2019-11-05 16:40:27 UTC (rev 252054)
@@ -44,6 +44,7 @@
 static bool webAuthenticationPanelSucceded = false;
 static bool webAuthenticationPanelUpdateMultipleNFCTagsPresent = false;
 static bool webAuthenticationPanelUpdateNoCredentialsFound = false;
+static bool webAuthenticationPanelCancelImmediately = false;
 static RetainPtr<_WKWebAuthenticationPanel> gPanel;
 
 @interface TestWebAuthenticationPanelDelegate : NSObject <_WKWebAuthenticationPanelDelegate>
@@ -54,6 +55,9 @@
 - (void)panel:(_WKWebAuthenticationPanel *)panel updateWebAuthenticationPanel:(_WKWebAuthenticationPanelUpdate)update
 {
     ASSERT_NE(panel, nil);
+    if (webAuthenticationPanelCancelImmediately)
+        [panel cancel];
+
     if (update == _WKWebAuthenticationPanelUpdateMultipleNFCTagsPresent) {
         webAuthenticationPanelUpdateMultipleNFCTagsPresent = true;
         return;
@@ -67,6 +71,9 @@
 - (void)panel:(_WKWebAuthenticationPanel *)panel dismissWebAuthenticationPanelWithResult:(_WKWebAuthenticationResult)result
 {
     ASSERT_NE(panel, nil);
+    if (webAuthenticationPanelCancelImmediately)
+        [panel cancel];
+
     if (result == _WKWebAuthenticationResultFailed) {
         webAuthenticationPanelFailed = true;
         return;
@@ -186,6 +193,7 @@
     webAuthenticationPanelRan = false;
     webAuthenticationPanelFailed = false;
     webAuthenticationPanelSucceded = false;
+    webAuthenticationPanelCancelImmediately = false;
     gPanel = nullptr;
 }
 
@@ -632,6 +640,59 @@
 }
 #endif
 
+TEST(WebAuthenticationPanel, PanelHidCancelReloadNoCrash)
+{
+    reset();
+    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-cancel" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+
+    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
+    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
+    auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+
+    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
+    Util::run(&webAuthenticationPanelRan);
+    [gPanel cancel];
+    [webView reload];
+    [webView waitForMessage:@"Operation timed out."];
+}
+
+TEST(WebAuthenticationPanel, PanelHidSuccessCancelNoCrash)
+{
+    reset();
+    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+
+    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
+    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
+    auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+    webAuthenticationPanelCancelImmediately = true;
+
+    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
+    [webView waitForMessage:@"Succeeded!"];
+}
+
+TEST(WebAuthenticationPanel, PanelHidCtapNoCredentialsFoundCancelNoCrash)
+{
+    reset();
+    RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"web-authentication-get-assertion-hid-no-credentials" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+
+    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
+    [[configuration preferences] _setEnabled:YES forExperimentalFeature:webAuthenticationExperimentalFeature()];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]);
+    auto delegate = adoptNS([[TestWebAuthenticationPanelUIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+    webAuthenticationPanelCancelImmediately = true;
+
+    [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]];
+    Util::run(&webAuthenticationPanelUpdateNoCredentialsFound);
+}
+
 } // namespace TestWebKitAPI
 
 #endif // ENABLE(WEB_AUTHN)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to