[PSON] process-swapping may occur even though opener has handle to openee
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Dec 2018 22:40:07 +0000 (22:40 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Dec 2018 22:40:07 +0000 (22:40 +0000)
https://bugs.webkit.org/show_bug.cgi?id=192277

Reviewed by Antti Koivisto.

Source/WebCore:

Process-swapping may occur even though opener has handle to openee, which is not Web-compatible. The reason
is that we rely on the window not having an opener to process-swap. However, the opener can be disowned,
which does not mean that the opener doesn't still have a handle to its openee.

To address the issue:
- Renamed openedViaWindowOpenWithOpener flag to openedByDOMWithOpener
- Make sure this flag gets set if an opener have ever been set for the browsing context
- Do not process-swap if this flag is set
- Drop opener from NavigationAction since it does not provide meaningful information to decide whether
  to process-swap or not.

* loader/FrameLoader.cpp:
(WebCore::FrameLoader::setOpener):
* loader/NavigationAction.h:
(WebCore::NavigationAction::openedByDOMWithOpener const):
(WebCore::NavigationAction::setOpenedByDOMWithOpener):
(WebCore::NavigationAction::setOpener): Deleted.
(WebCore::NavigationAction::opener const): Deleted.
(WebCore::NavigationAction::openedViaWindowOpenWithOpener const): Deleted.
(WebCore::NavigationAction::setOpenedViaWindowOpenWithOpener): Deleted.
* loader/PolicyChecker.cpp:
(WebCore::PolicyChecker::checkNavigationPolicy):
* page/DOMWindow.cpp:
(WebCore::DOMWindow::createWindow):
* page/Page.h:
(WebCore::Page::openedByDOMWithOpener const):
(WebCore::Page::setOpenedByDOMWithOpener):
(WebCore::Page::openedViaWindowOpenWithOpener const): Deleted.
(WebCore::Page::setOpenedViaWindowOpenWithOpener): Deleted.

Source/WebKit:

* Shared/NavigationActionData.cpp:
(WebKit::NavigationActionData::encode const):
(WebKit::NavigationActionData::decode):
* Shared/NavigationActionData.h:
* UIProcess/API/APINavigation.h:
(API::Navigation::openedByDOMWithOpener const):
(API::Navigation::openedViaWindowOpenWithOpener const): Deleted.
(API::Navigation::opener const): Deleted.
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::processForNavigationInternal):
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):

Tools:

Add API test coverage.

* TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@238787 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Source/WebCore/ChangeLog
Source/WebCore/loader/FrameLoader.cpp
Source/WebCore/loader/NavigationAction.h
Source/WebCore/loader/PolicyChecker.cpp
Source/WebCore/page/DOMWindow.cpp
Source/WebCore/page/Page.h
Source/WebKit/ChangeLog
Source/WebKit/Shared/NavigationActionData.cpp
Source/WebKit/Shared/NavigationActionData.h
Source/WebKit/UIProcess/API/APINavigation.h
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm

index f72c17b..3293bc6 100644 (file)
@@ -1,3 +1,40 @@
+2018-12-01  Chris Dumez  <cdumez@apple.com>
+
+        [PSON] process-swapping may occur even though opener has handle to openee
+        https://bugs.webkit.org/show_bug.cgi?id=192277
+
+        Reviewed by Antti Koivisto.
+
+        Process-swapping may occur even though opener has handle to openee, which is not Web-compatible. The reason
+        is that we rely on the window not having an opener to process-swap. However, the opener can be disowned,
+        which does not mean that the opener doesn't still have a handle to its openee.
+
+        To address the issue:
+        - Renamed openedViaWindowOpenWithOpener flag to openedByDOMWithOpener
+        - Make sure this flag gets set if an opener have ever been set for the browsing context
+        - Do not process-swap if this flag is set
+        - Drop opener from NavigationAction since it does not provide meaningful information to decide whether
+          to process-swap or not.
+
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::setOpener):
+        * loader/NavigationAction.h:
+        (WebCore::NavigationAction::openedByDOMWithOpener const):
+        (WebCore::NavigationAction::setOpenedByDOMWithOpener):
+        (WebCore::NavigationAction::setOpener): Deleted.
+        (WebCore::NavigationAction::opener const): Deleted.
+        (WebCore::NavigationAction::openedViaWindowOpenWithOpener const): Deleted.
+        (WebCore::NavigationAction::setOpenedViaWindowOpenWithOpener): Deleted.
+        * loader/PolicyChecker.cpp:
+        (WebCore::PolicyChecker::checkNavigationPolicy):
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::createWindow):
+        * page/Page.h:
+        (WebCore::Page::openedByDOMWithOpener const):
+        (WebCore::Page::setOpenedByDOMWithOpener):
+        (WebCore::Page::openedViaWindowOpenWithOpener const): Deleted.
+        (WebCore::Page::setOpenedViaWindowOpenWithOpener): Deleted.
+
 2018-12-01  Christopher Reid  <chris.reid@sony.com>
 
         Add generic implementations to FileSystemPOSIX.cpp
index 0d25554..2f1f2fd 100644 (file)
@@ -1048,8 +1048,11 @@ void FrameLoader::setOpener(Frame* opener)
         auto& openerFrameLoader = m_opener == &m_frame ? *this : m_opener->loader();
         openerFrameLoader.m_openedFrames.remove(&m_frame);
     }
-    if (opener)
+    if (opener) {
         opener->loader().m_openedFrames.add(&m_frame);
+        if (auto* page = m_frame.page())
+            page->setOpenedByDOMWithOpener();
+    }
     m_opener = opener;
 
     if (m_frame.document())
@@ -1478,13 +1481,6 @@ void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, Navig
     if (lockHistory == LockHistory::Yes && m_documentLoader)
         loader->setClientRedirectSourceForHistory(m_documentLoader->didCreateGlobalHistoryEntry() ? m_documentLoader->urlForHistory().string() : m_documentLoader->clientRedirectSourceForHistory());
 
-    if (auto* opener = this->opener()) {
-        auto pageID = opener->loader().client().pageID();
-        auto frameID = opener->loader().client().frameID();
-        if (pageID && frameID)
-            action.setOpener(std::make_pair(*pageID, *frameID));
-    }
-
     loader->setTriggeringAction(WTFMove(action));
     if (m_documentLoader)
         loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
index 39c564e..1e636ac 100644 (file)
@@ -118,14 +118,11 @@ public:
 
     bool treatAsSameOriginNavigation() const { return m_treatAsSameOriginNavigation; }
 
-    void setOpener(std::optional<PageIDAndFrameIDPair>&& opener) { m_opener = WTFMove(opener); }
-    const std::optional<PageIDAndFrameIDPair>& opener() const { return m_opener; }
-
     bool hasOpenedFrames() const { return m_hasOpenedFrames; }
     void setHasOpenedFrames(bool value) { m_hasOpenedFrames = value; }
 
-    bool openedViaWindowOpenWithOpener() const { return m_openedViaWindowOpenWithOpener; }
-    void setOpenedViaWindowOpenWithOpener() { m_openedViaWindowOpenWithOpener = true; }
+    bool openedByDOMWithOpener() const { return m_openedByDOMWithOpener; }
+    void setOpenedByDOMWithOpener() { m_openedByDOMWithOpener = true; }
 
     void setTargetBackForwardItem(HistoryItem&);
     const std::optional<BackForwardItemIdentifier>& targetBackForwardItemIdentifier() const { return m_targetBackForwardItemIdentifier; }
@@ -150,8 +147,7 @@ private:
     AtomicString m_downloadAttribute;
     bool m_treatAsSameOriginNavigation;
     bool m_hasOpenedFrames { false };
-    bool m_openedViaWindowOpenWithOpener { false };
-    std::optional<PageIDAndFrameIDPair> m_opener;
+    bool m_openedByDOMWithOpener { false };
     std::optional<BackForwardItemIdentifier> m_targetBackForwardItemIdentifier;
     LockHistory m_lockHistory { LockHistory::No };
     LockBackForwardList m_lockBackForwardList { LockBackForwardList::No };
index 5759fee..b9f2c53 100644 (file)
@@ -106,8 +106,8 @@ void PolicyChecker::checkNavigationPolicy(ResourceRequest&& request, const Resou
         loader->setTriggeringAction(NavigationAction { action });
     }
 
-    if (m_frame.page() && m_frame.page()->openedViaWindowOpenWithOpener())
-        action.setOpenedViaWindowOpenWithOpener();
+    if (m_frame.page() && m_frame.page()->openedByDOMWithOpener())
+        action.setOpenedByDOMWithOpener();
     action.setHasOpenedFrames(m_frame.loader().hasOpenedFrames());
 
     // Don't ask more than once for the same request or if we are loading an empty URL.
index 11c2769..9ed4101 100644 (file)
@@ -2237,10 +2237,9 @@ ExceptionOr<RefPtr<Frame>> DOMWindow::createWindow(const String& urlString, cons
     if (!newFrame)
         return RefPtr<Frame> { nullptr };
 
-    if (!windowFeatures.noopener) {
+    if (!windowFeatures.noopener)
         newFrame->loader().setOpener(&openerFrame);
-        newFrame->page()->setOpenedViaWindowOpenWithOpener();
-    }
+
     if (created)
         newFrame->page()->setOpenedByDOM();
 
index cb2e38f..411487f 100644 (file)
@@ -202,8 +202,8 @@ public:
     bool openedByDOM() const;
     void setOpenedByDOM();
 
-    bool openedViaWindowOpenWithOpener() const { return m_openedViaWindowOpenWithOpener; }
-    void setOpenedViaWindowOpenWithOpener() { m_openedViaWindowOpenWithOpener = true; }
+    bool openedByDOMWithOpener() const { return m_openedByDOMWithOpener; }
+    void setOpenedByDOMWithOpener() { m_openedByDOMWithOpener = true; }
 
     WEBCORE_EXPORT void goToItem(HistoryItem&, FrameLoadType, ShouldTreatAsContinuingLoad);
 
@@ -766,7 +766,7 @@ private:
     int m_subframeCount { 0 };
     String m_groupName;
     bool m_openedByDOM { false };
-    bool m_openedViaWindowOpenWithOpener { false };
+    bool m_openedByDOMWithOpener { false };
 
     bool m_tabKeyCyclesThroughElements { true };
     bool m_defersLoading { false };
index f080e92..9783723 100644 (file)
@@ -1,3 +1,23 @@
+2018-12-01  Chris Dumez  <cdumez@apple.com>
+
+        [PSON] process-swapping may occur even though opener has handle to openee
+        https://bugs.webkit.org/show_bug.cgi?id=192277
+
+        Reviewed by Antti Koivisto.
+
+        * Shared/NavigationActionData.cpp:
+        (WebKit::NavigationActionData::encode const):
+        (WebKit::NavigationActionData::decode):
+        * Shared/NavigationActionData.h:
+        * UIProcess/API/APINavigation.h:
+        (API::Navigation::openedByDOMWithOpener const):
+        (API::Navigation::openedViaWindowOpenWithOpener const): Deleted.
+        (API::Navigation::opener const): Deleted.
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::processForNavigationInternal):
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):
+
 2018-12-01  Alexey Proskuryakov  <ap@apple.com>
 
         Modernize version check for _suppressedAutoAddedHTTPHeaders
index 38722e9..672059e 100644 (file)
@@ -47,8 +47,7 @@ void NavigationActionData::encode(IPC::Encoder& encoder) const
     encoder << isRedirect;
     encoder << treatAsSameOriginNavigation;
     encoder << hasOpenedFrames;
-    encoder << openedViaWindowOpenWithOpener;
-    encoder << opener;
+    encoder << openedByDOMWithOpener;
     encoder << requesterOrigin;
     encoder << targetBackForwardItemIdentifier;
     encoder.encodeEnum(lockHistory);
@@ -112,19 +111,14 @@ std::optional<NavigationActionData> NavigationActionData::decode(IPC::Decoder& d
     if (!hasOpenedFrames)
         return std::nullopt;
 
-    std::optional<bool> openedViaWindowOpenWithOpener;
-    decoder >> openedViaWindowOpenWithOpener;
-    if (!openedViaWindowOpenWithOpener)
-        return std::nullopt;
-
-    std::optional<std::optional<std::pair<uint64_t, uint64_t>>> opener;
-    decoder >> opener;
-    if (!opener)
+    std::optional<bool> openedByDOMWithOpener;
+    decoder >> openedByDOMWithOpener;
+    if (!openedByDOMWithOpener)
         return std::nullopt;
 
     std::optional<WebCore::SecurityOriginData> requesterOrigin;
     decoder >> requesterOrigin;
-    if (!opener)
+    if (!requesterOrigin)
         return std::nullopt;
 
     std::optional<std::optional<WebCore::BackForwardItemIdentifier>> targetBackForwardItemIdentifier;
@@ -147,7 +141,7 @@ std::optional<NavigationActionData> NavigationActionData::decode(IPC::Decoder& d
 
     return {{ WTFMove(navigationType), WTFMove(modifiers), WTFMove(mouseButton), WTFMove(syntheticClickType), WTFMove(*userGestureTokenIdentifier),
         WTFMove(*canHandleRequest), WTFMove(shouldOpenExternalURLsPolicy), WTFMove(*downloadAttribute), WTFMove(clickLocationInRootViewCoordinates),
-        WTFMove(*isRedirect), *treatAsSameOriginNavigation, *hasOpenedFrames, *openedViaWindowOpenWithOpener, WTFMove(*opener), WTFMove(*requesterOrigin),
+        WTFMove(*isRedirect), *treatAsSameOriginNavigation, *hasOpenedFrames, *openedByDOMWithOpener, WTFMove(*requesterOrigin),
         WTFMove(*targetBackForwardItemIdentifier), lockHistory, lockBackForwardList, WTFMove(*clientRedirectSourceForHistory) }};
 }
 
index 16f9767..1285586 100644 (file)
@@ -54,8 +54,7 @@ struct NavigationActionData {
     bool isRedirect { false };
     bool treatAsSameOriginNavigation { false };
     bool hasOpenedFrames { false };
-    bool openedViaWindowOpenWithOpener { false };
-    std::optional<std::pair<uint64_t, uint64_t>> opener;
+    bool openedByDOMWithOpener { false };
     WebCore::SecurityOriginData requesterOrigin;
     std::optional<WebCore::BackForwardItemIdentifier> targetBackForwardItemIdentifier;
     WebCore::LockHistory lockHistory;
index a9f6228..f9e7105 100644 (file)
@@ -118,8 +118,7 @@ public:
 
     bool treatAsSameOriginNavigation() const { return m_lastNavigationAction.treatAsSameOriginNavigation; }
     bool hasOpenedFrames() const { return m_lastNavigationAction.hasOpenedFrames; }
-    bool openedViaWindowOpenWithOpener() const { return m_lastNavigationAction.openedViaWindowOpenWithOpener; }
-    const std::optional<std::pair<uint64_t, uint64_t>>& opener() const { return m_lastNavigationAction.opener; }
+    bool openedByDOMWithOpener() const { return m_lastNavigationAction.openedByDOMWithOpener; }
     const WebCore::SecurityOriginData& requesterOrigin() const { return m_lastNavigationAction.requesterOrigin; }
 
     WebCore::LockHistory lockHistory() const { return m_lastNavigationAction.lockHistory; }
index 5c4d768..88c1845 100644 (file)
@@ -2157,14 +2157,8 @@ Ref<WebProcessProxy> WebProcessPool::processForNavigationInternal(WebPageProxy&
 
     // FIXME: We should support process swap when a window has been opened via window.open() without 'noopener'.
     // The issue is that the opener has a handle to the WindowProxy.
-    if (navigation.openedViaWindowOpenWithOpener() && !m_configuration->processSwapsOnWindowOpenWithOpener()) {
-        reason = "Browsing context been opened via window.open() without 'noopener'"_s;
-        return page.process();
-    }
-
-    // FIXME: We should support process swap when a window has an opener.
-    if (navigation.opener() && !m_configuration->processSwapsOnWindowOpenWithOpener()) {
-        reason = "Browsing context has an opener"_s;
+    if (navigation.openedByDOMWithOpener() && !m_configuration->processSwapsOnWindowOpenWithOpener()) {
+        reason = "Browsing context been opened by DOM without 'noopener'"_s;
         return page.process();
     }
 
index 6958e07..91ba79e 100644 (file)
@@ -873,8 +873,7 @@ void WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(const Navigat
     navigationActionData.isRedirect = !redirectResponse.isNull();
     navigationActionData.treatAsSameOriginNavigation = navigationAction.treatAsSameOriginNavigation();
     navigationActionData.hasOpenedFrames = navigationAction.hasOpenedFrames();
-    navigationActionData.openedViaWindowOpenWithOpener = navigationAction.openedViaWindowOpenWithOpener();
-    navigationActionData.opener = navigationAction.opener();
+    navigationActionData.openedByDOMWithOpener = navigationAction.openedByDOMWithOpener();
     if (auto& requester = navigationAction.requester())
         navigationActionData.requesterOrigin = requester->securityOrigin().data();
     navigationActionData.targetBackForwardItemIdentifier = navigationAction.targetBackForwardItemIdentifier();
index 1f4ad67..26023ac 100644 (file)
@@ -1,3 +1,14 @@
+2018-12-01  Chris Dumez  <cdumez@apple.com>
+
+        [PSON] process-swapping may occur even though opener has handle to openee
+        https://bugs.webkit.org/show_bug.cgi?id=192277
+
+        Reviewed by Antti Koivisto.
+
+        Add API test coverage.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+
 2018-12-01  Jonathan Bedard  <jbedard@apple.com>
 
         Unreviewed, rolling out r238764.
index fc9571d..e127ce3 100644 (file)
@@ -2977,6 +2977,145 @@ TEST(ProcessSwap, NavigateCrossOriginWithOpenee)
     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
 }
 
+static const char* crossSiteLinkWithOpenerTestBytes = R"PSONRESOURCE(
+<script>
+function saveOpenee()
+{
+    openee = window.open("", "foo");
+}
+</script>
+<a id="testLink" target="foo" href="pson://www.webkit.org/main2.html">Link</a>
+)PSONRESOURCE";
+
+TEST(ProcessSwap, NavigateCrossOriginWithOpener)
+{
+    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
+    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
+
+    auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [webViewConfiguration setProcessPool:processPool.get()];
+    auto handler = adoptNS([[PSONScheme alloc] init]);
+    [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:crossSiteLinkWithOpenerTestBytes];
+    [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
+
+    auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
+    [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+    auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
+    [webView setNavigationDelegate:navigationDelegate.get()];
+    auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
+
+    [webView loadRequest:request];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    // Opens "pson://www.webkit.org/main2.html" in an auxiliary window.
+    [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil];
+
+    TestWebKitAPI::Util::run(&didCreateWebView);
+    didCreateWebView = false;
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    EXPECT_EQ([webView _webProcessIdentifier], [createdWebView _webProcessIdentifier]);
+    auto webkitPID = [webView _webProcessIdentifier];
+
+    EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", [[webView URL] absoluteString]);
+    EXPECT_WK_STREQ(@"pson://www.webkit.org/main2.html", [[createdWebView URL] absoluteString]);
+
+    [webView evaluateJavaScript:@"saveOpenee()" completionHandler: [&] (id, NSError *error) {
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    [webView evaluateJavaScript:@"openee.location.href" completionHandler: [&] (id openeeURL, NSError *error) {
+        EXPECT_WK_STREQ(@"pson://www.webkit.org/main2.html", openeeURL);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    // New window should have an opener.
+    [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpener, NSError *error) {
+        EXPECT_WK_STREQ(@"true", hasOpener);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    // Navigate auxiliary window cross-origin.
+    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
+    [createdWebView loadRequest:request];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[createdWebView URL] absoluteString]);
+
+    // Auxiliary window should still have an opener.
+    [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpener, NSError *error) {
+        EXPECT_WK_STREQ(@"true", hasOpener);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    [createdWebView evaluateJavaScript:@"window.opener.closed ? 'true' : 'false'" completionHandler: [&] (id openerIsClosed, NSError *error) {
+        EXPECT_WK_STREQ(@"false", openerIsClosed);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    // We should not have process-swapped since the auxiliary window has an opener.
+    EXPECT_EQ(webkitPID, [createdWebView _webProcessIdentifier]);
+
+    // Have the openee disown its opener.
+    [createdWebView evaluateJavaScript:@"window.opener = null" completionHandler: [&] (id, NSError *error) {
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    // Auxiliary window should not have an opener.
+    [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpener, NSError *error) {
+        EXPECT_WK_STREQ(@"false", hasOpener);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    // Navigate openee cross-origin again.
+    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
+    [createdWebView loadRequest:request];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    // Auxiliary window should not have an opener.
+    [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpener, NSError *error) {
+        EXPECT_WK_STREQ(@"false", hasOpener);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    EXPECT_WK_STREQ(@"pson://www.google.com/main.html", [[createdWebView URL] absoluteString]);
+    // We still should not have process-swapped since the auxiliary window's opener still has a handle to its openee.
+    EXPECT_EQ(webkitPID, [createdWebView _webProcessIdentifier]);
+
+    [webView evaluateJavaScript:@"openee.closed ? 'true' : 'false'" completionHandler: [&] (id openeeIsClosed, NSError *error) {
+        EXPECT_WK_STREQ(@"false", openeeIsClosed);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+}
+
 TEST(ProcessSwap, GoBackToSuspendedPageWithMainFrameIDThatIsNotOne)
 {
     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);