Title: [235994] trunk
Revision
235994
Author
[email protected]
Date
2018-09-13 15:38:25 -0700 (Thu, 13 Sep 2018)

Log Message

Regression(PSON): setting window.opener to null allows process swapping in cases that are not web-compatible
https://bugs.webkit.org/show_bug.cgi?id=189590
<rdar://problem/44422725>

Reviewed by Geoffrey Garen.

Source/WebCore:

Set a flag on the navigation action to indicate if the page was opened via window.open() without 'noopener'.

Test: http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin.html

* loader/FrameLoader.cpp:
(WebCore::FrameLoader::loadURL):
* loader/NavigationAction.h:
(WebCore::NavigationAction::openedViaWindowOpenWithOpener const):
(WebCore::NavigationAction::setOpenedViaWindowOpenWithOpener):
* page/DOMWindow.cpp:
(WebCore::DOMWindow::createWindow):
* page/Page.h:
(WebCore::Page::openedViaWindowOpenWithOpener const):
(WebCore::Page::setOpenedViaWindowOpenWithOpener):

Source/WebKit:

If script calls window.open() without 'noopener' and the newly navigated window gets navigated cross-site,
we are currently unable to process-swap because the opener has a WindowProxy handle to this new Window and
may interact with it (which we currently do not support cross-process). We were dealing with this by not
process-swapping if window.opener is not null. This works most of the time but is not sufficient because the
opener may get nulled out, while the opener still has a valid WindowProxy handle to its openee.

Therefore, we now also check for a flag indicating if the frame was opened via window.open() without
'nooopener'. We still need to check if the browsing context has an opener for browsing context created
via <a target="_blank"> for example (the opener does not have a handle to the new window but the openee
has access to its opener).

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

LayoutTests:

Add layout test coverage.

* http/tests/navigation/resources/navigate-helper.html: Added.
* http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin-expected.txt: Added.
* http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (235993 => 235994)


--- trunk/LayoutTests/ChangeLog	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/LayoutTests/ChangeLog	2018-09-13 22:38:25 UTC (rev 235994)
@@ -1,3 +1,17 @@
+2018-09-13  Chris Dumez  <[email protected]>
+
+        Regression(PSON): setting window.opener to null allows process swapping in cases that are not web-compatible
+        https://bugs.webkit.org/show_bug.cgi?id=189590
+        <rdar://problem/44422725>
+
+        Reviewed by Geoffrey Garen.
+
+        Add layout test coverage.
+
+        * http/tests/navigation/resources/navigate-helper.html: Added.
+        * http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin-expected.txt: Added.
+        * http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin.html: Added.
+
 2018-09-13  Dean Jackson  <[email protected]>
 
         https://bugs.webkit.org/show_bug.cgi?id=189594

Added: trunk/LayoutTests/http/tests/navigation/resources/navigate-helper.html (0 => 235994)


--- trunk/LayoutTests/http/tests/navigation/resources/navigate-helper.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/navigation/resources/navigate-helper.html	2018-09-13 22:38:25 UTC (rev 235994)
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+_onmessage_ = (msg) => {
+    setTimeout(() => {
+        window.location = msg.data.navigate;
+    }, 0);
+};
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin-expected.txt (0 => 235994)


--- trunk/LayoutTests/http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin-expected.txt	2018-09-13 22:38:25 UTC (rev 235994)
@@ -0,0 +1,10 @@
+Tests that process swap on navigation does not break navigating back cross-origin a cross-origin window.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS w.location.href is "http://127.0.0.1:8000/navigation/resources/otherpage.html"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin.html (0 => 235994)


--- trunk/LayoutTests/http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin.html	2018-09-13 22:38:25 UTC (rev 235994)
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script>
+description("Tests that process swap on navigation does not break navigating back cross-origin a cross-origin window.");
+jsTestIsAsync = true;
+
+if (window.testRunner)
+    testRunner.setCanOpenWindows();
+
+function wasNavigatedSameOrigin()
+{
+    shouldBeEqualToString("w.location.href", "http://127.0.0.1:8000/navigation/resources/otherpage.html");
+    finishJSTest();
+}
+
+function wasNavigatedCrossOrigin()
+{
+    // Navigate back same origin.
+    w.postMessage({ navigate: "http://127.0.0.1:8000/navigation/resources/otherpage.html" }, "*");
+    handle = setInterval(() => {
+        try {
+            w.name;
+            clearInterval(handle);
+            wasNavigatedSameOrigin();
+        } catch(e) {
+        }
+    }, 10);
+}
+
+_onload_ = function() {
+    w = window.open();
+    w.opener = null;
+    w.location = "http://localhost:8000/navigation/resources/navigate-helper.html";
+    handle = setInterval(() => {
+        try {
+            w.name;
+        } catch(e) {
+            clearInterval(handle);
+            wasNavigatedCrossOrigin();
+        }
+    }, 10);
+}
+</script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (235993 => 235994)


--- trunk/Source/WebCore/ChangeLog	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebCore/ChangeLog	2018-09-13 22:38:25 UTC (rev 235994)
@@ -1,3 +1,26 @@
+2018-09-13  Chris Dumez  <[email protected]>
+
+        Regression(PSON): setting window.opener to null allows process swapping in cases that are not web-compatible
+        https://bugs.webkit.org/show_bug.cgi?id=189590
+        <rdar://problem/44422725>
+
+        Reviewed by Geoffrey Garen.
+
+        Set a flag on the navigation action to indicate if the page was opened via window.open() without 'noopener'.
+
+        Test: http/tests/navigation/window-open-cross-origin-then-navigated-back-same-origin.html
+
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::loadURL):
+        * loader/NavigationAction.h:
+        (WebCore::NavigationAction::openedViaWindowOpenWithOpener const):
+        (WebCore::NavigationAction::setOpenedViaWindowOpenWithOpener):
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::createWindow):
+        * page/Page.h:
+        (WebCore::Page::openedViaWindowOpenWithOpener const):
+        (WebCore::Page::setOpenedViaWindowOpenWithOpener):
+
 2018-09-13  Jer Noble  <[email protected]>
 
         Enable USE_MEDIAREMOTE on iOS

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (235993 => 235994)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2018-09-13 22:38:25 UTC (rev 235994)
@@ -1364,6 +1364,8 @@
 
     NavigationAction action { frameLoadRequest.requester(), request, frameLoadRequest.initiatedByMainFrame(), newLoadType, isFormSubmission, event, frameLoadRequest.shouldOpenExternalURLsPolicy(), frameLoadRequest.downloadAttribute() };
     action.setIsCrossOriginWindowOpenNavigation(frameLoadRequest.isCrossOriginWindowOpenNavigation());
+    if (m_frame.page() && m_frame.page()->openedViaWindowOpenWithOpener())
+        action.setOpenedViaWindowOpenWithOpener();
     action.setHasOpenedFrames(!m_openedFrames.isEmpty());
     if (auto* opener = this->opener()) {
         auto pageID = opener->loader().client().pageID();

Modified: trunk/Source/WebCore/loader/NavigationAction.h (235993 => 235994)


--- trunk/Source/WebCore/loader/NavigationAction.h	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebCore/loader/NavigationAction.h	2018-09-13 22:38:25 UTC (rev 235994)
@@ -126,6 +126,9 @@
     bool hasOpenedFrames() const { return m_hasOpenedFrames; }
     void setHasOpenedFrames(bool value) { m_hasOpenedFrames = value; }
 
+    bool openedViaWindowOpenWithOpener() const { return m_openedViaWindowOpenWithOpener; }
+    void setOpenedViaWindowOpenWithOpener() { m_openedViaWindowOpenWithOpener = true; }
+
     void setTargetBackForwardItem(HistoryItem&);
     const std::optional<BackForwardItemIdentifier>& targetBackForwardItemIdentifier() const { return m_targetBackForwardItemIdentifier; }
 
@@ -144,6 +147,7 @@
     bool m_treatAsSameOriginNavigation;
     bool m_isCrossOriginWindowOpenNavigation { false };
     bool m_hasOpenedFrames { false };
+    bool m_openedViaWindowOpenWithOpener { false };
     std::optional<PageIDAndFrameIDPair> m_opener;
     std::optional<BackForwardItemIdentifier> m_targetBackForwardItemIdentifier;
 };

Modified: trunk/Source/WebCore/page/DOMWindow.cpp (235993 => 235994)


--- trunk/Source/WebCore/page/DOMWindow.cpp	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebCore/page/DOMWindow.cpp	2018-09-13 22:38:25 UTC (rev 235994)
@@ -2264,8 +2264,10 @@
     if (!newFrame)
         return RefPtr<Frame> { nullptr };
 
-    if (!windowFeatures.noopener)
+    if (!windowFeatures.noopener) {
         newFrame->loader().setOpener(&openerFrame);
+        newFrame->page()->setOpenedViaWindowOpenWithOpener();
+    }
     newFrame->page()->setOpenedByDOM();
 
     if (newFrame->document()->domWindow()->isInsecureScriptAccess(activeWindow, completedURL))

Modified: trunk/Source/WebCore/page/Page.h (235993 => 235994)


--- trunk/Source/WebCore/page/Page.h	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebCore/page/Page.h	2018-09-13 22:38:25 UTC (rev 235994)
@@ -202,6 +202,9 @@
     bool openedByDOM() const;
     void setOpenedByDOM();
 
+    bool openedViaWindowOpenWithOpener() const { return m_openedViaWindowOpenWithOpener; }
+    void setOpenedViaWindowOpenWithOpener() { m_openedViaWindowOpenWithOpener = true; }
+
     WEBCORE_EXPORT void goToItem(HistoryItem&, FrameLoadType, ShouldTreatAsContinuingLoad);
 
     WEBCORE_EXPORT void setGroupName(const String&);
@@ -750,6 +753,7 @@
     int m_subframeCount { 0 };
     String m_groupName;
     bool m_openedByDOM { false };
+    bool m_openedViaWindowOpenWithOpener { false };
 
     bool m_tabKeyCyclesThroughElements { true };
     bool m_defersLoading { false };

Modified: trunk/Source/WebKit/ChangeLog (235993 => 235994)


--- trunk/Source/WebKit/ChangeLog	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebKit/ChangeLog	2018-09-13 22:38:25 UTC (rev 235994)
@@ -1,3 +1,36 @@
+2018-09-13  Chris Dumez  <[email protected]>
+
+        Regression(PSON): setting window.opener to null allows process swapping in cases that are not web-compatible
+        https://bugs.webkit.org/show_bug.cgi?id=189590
+        <rdar://problem/44422725>
+
+        Reviewed by Geoffrey Garen.
+
+        If script calls window.open() without 'noopener' and the newly navigated window gets navigated cross-site,
+        we are currently unable to process-swap because the opener has a WindowProxy handle to this new Window and
+        may interact with it (which we currently do not support cross-process). We were dealing with this by not
+        process-swapping if window.opener is not null. This works most of the time but is not sufficient because the
+        opener may get nulled out, while the opener still has a valid WindowProxy handle to its openee.
+
+        Therefore, we now also check for a flag indicating if the frame was opened via window.open() without
+        'nooopener'. We still need to check if the browsing context has an opener for browsing context created
+        via <a target="_blank"> for example (the opener does not have a handle to the new window but the openee
+        has access to its opener).
+
+        * Shared/NavigationActionData.cpp:
+        (WebKit::NavigationActionData::encode const):
+        (WebKit::NavigationActionData::decode):
+        * Shared/NavigationActionData.h:
+        * UIProcess/API/APINavigation.h:
+        (API::Navigation::openedViaWindowOpenWithOpener const):
+        (API::Navigation::setOpenedViaWindowOpenWithOpener):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::decidePolicyForNavigationAction):
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::processForNavigationInternal):
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):
+
 2018-09-13  Dean Jackson  <[email protected]>
 
         Generate warnings for Preferences files

Modified: trunk/Source/WebKit/Shared/NavigationActionData.cpp (235993 => 235994)


--- trunk/Source/WebKit/Shared/NavigationActionData.cpp	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebKit/Shared/NavigationActionData.cpp	2018-09-13 22:38:25 UTC (rev 235994)
@@ -48,6 +48,7 @@
     encoder << treatAsSameOriginNavigation;
     encoder << isCrossOriginWindowOpenNavigation;
     encoder << hasOpenedFrames;
+    encoder << openedViaWindowOpenWithOpener;
     encoder << opener;
     encoder << targetBackForwardItemIdentifier;
 }
@@ -113,6 +114,11 @@
     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)
@@ -125,7 +131,7 @@
         
     return {{ WTFMove(navigationType), WTFMove(modifiers), WTFMove(mouseButton), WTFMove(syntheticClickType), WTFMove(*userGestureTokenIdentifier),
         WTFMove(*canHandleRequest), WTFMove(shouldOpenExternalURLsPolicy), WTFMove(*downloadAttribute), WTFMove(clickLocationInRootViewCoordinates),
-        WTFMove(*isRedirect), *treatAsSameOriginNavigation, *isCrossOriginWindowOpenNavigation, *hasOpenedFrames, WTFMove(*opener), WTFMove(*targetBackForwardItemIdentifier) }};
+        WTFMove(*isRedirect), *treatAsSameOriginNavigation, *isCrossOriginWindowOpenNavigation, *hasOpenedFrames, *openedViaWindowOpenWithOpener, WTFMove(*opener), WTFMove(*targetBackForwardItemIdentifier) }};
 }
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/Shared/NavigationActionData.h (235993 => 235994)


--- trunk/Source/WebKit/Shared/NavigationActionData.h	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebKit/Shared/NavigationActionData.h	2018-09-13 22:38:25 UTC (rev 235994)
@@ -54,6 +54,7 @@
     bool treatAsSameOriginNavigation { false };
     bool isCrossOriginWindowOpenNavigation { false };
     bool hasOpenedFrames { false };
+    bool openedViaWindowOpenWithOpener { false };
     std::optional<std::pair<uint64_t, uint64_t>> opener;
     std::optional<WebCore::BackForwardItemIdentifier> targetBackForwardItemIdentifier;
 };

Modified: trunk/Source/WebKit/UIProcess/API/APINavigation.h (235993 => 235994)


--- trunk/Source/WebKit/UIProcess/API/APINavigation.h	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebKit/UIProcess/API/APINavigation.h	2018-09-13 22:38:25 UTC (rev 235994)
@@ -94,6 +94,9 @@
     void setHasOpenedFrames(bool value) { m_hasOpenedFrames = value; }
     bool hasOpenedFrames() const { return m_hasOpenedFrames; }
 
+    bool openedViaWindowOpenWithOpener() const { return m_openedViaWindowOpenWithOpener; }
+    void setOpenedViaWindowOpenWithOpener() { m_openedViaWindowOpenWithOpener = true; }
+
     void setOpener(const std::optional<std::pair<uint64_t, uint64_t>>& opener) { m_opener = opener; }
     const std::optional<std::pair<uint64_t, uint64_t>>& opener() const { return m_opener; }
 
@@ -121,6 +124,7 @@
     bool m_treatAsSameOriginNavigation { false };
     bool m_isCrossOriginWindowOpenNavigation { false };
     bool m_hasOpenedFrames { false };
+    bool m_openedViaWindowOpenWithOpener { false };
     std::optional<std::pair<uint64_t, uint64_t>> m_opener;
 };
 

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (235993 => 235994)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2018-09-13 22:38:25 UTC (rev 235994)
@@ -4022,6 +4022,8 @@
     navigation->setTreatAsSameOriginNavigation(navigationActionData.treatAsSameOriginNavigation);
     navigation->setIsCrossOriginWindowOpenNavigation(navigationActionData.isCrossOriginWindowOpenNavigation);
     navigation->setHasOpenedFrames(navigationActionData.hasOpenedFrames);
+    if (navigationActionData.openedViaWindowOpenWithOpener)
+        navigation->setOpenedViaWindowOpenWithOpener();
     navigation->setOpener(navigationActionData.opener);
 
 #if ENABLE(CONTENT_FILTERING)

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (235993 => 235994)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2018-09-13 22:38:25 UTC (rev 235994)
@@ -2153,6 +2153,13 @@
         return createNewWebProcess(page.websiteDataStore());
     }
 
+    // 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()) {
+        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()) {
         reason = "Browsing context has an opener"_s;

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp (235993 => 235994)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp	2018-09-13 22:33:10 UTC (rev 235993)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp	2018-09-13 22:38:25 UTC (rev 235994)
@@ -868,6 +868,7 @@
     navigationActionData.treatAsSameOriginNavigation = navigationAction.treatAsSameOriginNavigation();
     navigationActionData.isCrossOriginWindowOpenNavigation = navigationAction.isCrossOriginWindowOpenNavigation();
     navigationActionData.hasOpenedFrames = navigationAction.hasOpenedFrames();
+    navigationActionData.openedViaWindowOpenWithOpener = navigationAction.openedViaWindowOpenWithOpener();
     navigationActionData.opener = navigationAction.opener();
     navigationActionData.targetBackForwardItemIdentifier = navigationAction.targetBackForwardItemIdentifier();
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to