Title: [248410] trunk
Revision
248410
Author
beid...@apple.com
Date
2019-08-08 08:54:37 -0700 (Thu, 08 Aug 2019)

Log Message

Do not allow navigations of frames about to get replaced by the result of evaluating _javascript_: URLs
<rdar://problem/53788893> and https://bugs.webkit.org/show_bug.cgi?id=198786

Reviewed by Geoff Garen.

Source/WebCore:

Covered by API Test

Add a "willReplaceWithResultOfExecutingJavascriptURL" flag which is respected inside FrameLoader::isNavigationAllowed

* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::executeIfJavaScriptURL):
* bindings/js/ScriptController.h:
(WebCore::ScriptController::willReplaceWithResultOfExecutingJavascriptURL const):

* loader/FrameLoader.cpp:
(WebCore::FrameLoader::isNavigationAllowed const):

Tools:

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/mac/_javascript_URLNavigation.mm: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (248409 => 248410)


--- trunk/Source/WebCore/ChangeLog	2019-08-08 14:55:21 UTC (rev 248409)
+++ trunk/Source/WebCore/ChangeLog	2019-08-08 15:54:37 UTC (rev 248410)
@@ -1,3 +1,22 @@
+2019-08-08  Brady Eidson  <beid...@apple.com>
+
+        Do not allow navigations of frames about to get replaced by the result of evaluating _javascript_: URLs
+        <rdar://problem/53788893> and https://bugs.webkit.org/show_bug.cgi?id=198786
+
+        Reviewed by Geoff Garen.
+
+        Covered by API Test
+
+        Add a "willReplaceWithResultOfExecutingJavascriptURL" flag which is respected inside FrameLoader::isNavigationAllowed
+
+        * bindings/js/ScriptController.cpp:
+        (WebCore::ScriptController::executeIfJavaScriptURL):
+        * bindings/js/ScriptController.h:
+        (WebCore::ScriptController::willReplaceWithResultOfExecutingJavascriptURL const):
+
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::isNavigationAllowed const):
+
 2019-08-08  Rob Buis  <rb...@igalia.com>
 
         Add runtime flag for lazy image loading

Modified: trunk/Source/WebCore/bindings/js/ScriptController.cpp (248409 => 248410)


--- trunk/Source/WebCore/bindings/js/ScriptController.cpp	2019-08-08 14:55:21 UTC (rev 248409)
+++ trunk/Source/WebCore/bindings/js/ScriptController.cpp	2019-08-08 15:54:37 UTC (rev 248410)
@@ -648,8 +648,14 @@
     if (shouldReplaceDocumentIfJavaScriptURL == ReplaceDocumentIfJavaScriptURL) {
         // We're still in a frame, so there should be a DocumentLoader.
         ASSERT(m_frame.document()->loader());
-        
-        // DocumentWriter::replaceDocument can cause the DocumentLoader to get deref'ed and possible destroyed,
+
+        // Signal to FrameLoader to disable navigations within this frame while replacing it with the result of executing _javascript_
+        // FIXME: https://bugs.webkit.org/show_bug.cgi?id=200523
+        // The only reason we do a nestable save/restore of this flag here is because we sometimes nest _javascript_: url loads as
+        // some will load synchronously. We'd like to remove those synchronous loads and then change this.
+        SetForScope<bool> willBeReplaced(m_willReplaceWithResultOfExecutingJavascriptURL, true);
+
+        // DocumentWriter::replaceDocumentWithResultOfExecutingJavascriptURL can cause the DocumentLoader to get deref'ed and possible destroyed,
         // so protect it with a RefPtr.
         if (RefPtr<DocumentLoader> loader = m_frame.document()->loader())
             loader->writer().replaceDocumentWithResultOfExecutingJavascriptURL(scriptResult, ownerDocument.get());

Modified: trunk/Source/WebCore/bindings/js/ScriptController.h (248409 => 248410)


--- trunk/Source/WebCore/bindings/js/ScriptController.h	2019-08-08 14:55:21 UTC (rev 248409)
+++ trunk/Source/WebCore/bindings/js/ScriptController.h	2019-08-08 15:54:37 UTC (rev 248410)
@@ -163,6 +163,8 @@
 
     void initScriptForWindowProxy(JSWindowProxy&);
 
+    bool willReplaceWithResultOfExecutingJavascriptURL() const { return m_willReplaceWithResultOfExecutingJavascriptURL; }
+
 private:
     void setupModuleScriptHandlers(LoadableModuleScript&, JSC::JSInternalPromise&, DOMWrapperWorld&);
 
@@ -175,6 +177,7 @@
     const String* m_sourceURL;
 
     bool m_paused;
+    bool m_willReplaceWithResultOfExecutingJavascriptURL { false };
 
     // The root object used for objects bound outside the context of a plugin, such
     // as NPAPI plugins. The plugins using these objects prevent a page from being cached so they

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (248409 => 248410)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2019-08-08 14:55:21 UTC (rev 248409)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2019-08-08 15:54:37 UTC (rev 248410)
@@ -1324,7 +1324,7 @@
 
 bool FrameLoader::isNavigationAllowed() const
 {
-    return m_pageDismissalEventBeingDispatched == PageDismissalType::None && NavigationDisabler::isNavigationAllowed(m_frame);
+    return m_pageDismissalEventBeingDispatched == PageDismissalType::None && !m_frame.script().willReplaceWithResultOfExecutingJavascriptURL() && NavigationDisabler::isNavigationAllowed(m_frame);
 }
 
 bool FrameLoader::isStopLoadingAllowed() const

Modified: trunk/Tools/ChangeLog (248409 => 248410)


--- trunk/Tools/ChangeLog	2019-08-08 14:55:21 UTC (rev 248409)
+++ trunk/Tools/ChangeLog	2019-08-08 15:54:37 UTC (rev 248410)
@@ -1,3 +1,13 @@
+2019-08-08  Brady Eidson  <beid...@apple.com>
+
+        Do not allow navigations of frames about to get replaced by the result of evaluating _javascript_: URLs
+        <rdar://problem/53788893> and https://bugs.webkit.org/show_bug.cgi?id=198786
+
+        Reviewed by Geoff Garen.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/mac/_javascript_URLNavigation.mm: Added.
+
 2019-08-08  Rob Buis  <rb...@igalia.com>
 
         Add runtime flag for lazy image loading

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (248409 => 248410)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2019-08-08 14:55:21 UTC (rev 248409)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2019-08-08 15:54:37 UTC (rev 248410)
@@ -251,6 +251,7 @@
 		51714EB51CF8C78C004723C4 /* WebProcessKillIDBCleanup-2.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 51714EB31CF8C761004723C4 /* WebProcessKillIDBCleanup-2.html */; };
 		51714EB81CF8CA17004723C4 /* WebProcessKillIDBCleanup.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51714EB61CF8C7A4004723C4 /* WebProcessKillIDBCleanup.mm */; };
 		517E7E04151119C100D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 517E7E031511187500D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.html */; };
+		51820A4D22F4EE7F00DF0A01 /* _javascript_URLNavigation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51820A4C22F4EE7700DF0A01 /* _javascript_URLNavigation.mm */; };
 		5182C22E1F2BCE540059BA7C /* WKURLSchemeHandler-leaks.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5182C22D1F2BCB410059BA7C /* WKURLSchemeHandler-leaks.mm */; };
 		518C1153205B0504001FF4AE /* ProcessSwapOnNavigation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 518C1152205B04F9001FF4AE /* ProcessSwapOnNavigation.mm */; };
 		518EE51820A78CE200E024F3 /* DoubleDefersLoading.mm in Sources */ = {isa = PBXBuildFile; fileRef = 518EE51620A78CDF00E024F3 /* DoubleDefersLoading.mm */; };
@@ -1717,6 +1718,7 @@
 		51714EB91D087416004723C4 /* CrossThreadTask.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CrossThreadTask.cpp; sourceTree = "<group>"; };
 		517E7DFB15110EA600D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MemoryCachePruneWithinResourceLoadDelegate.mm; sourceTree = "<group>"; };
 		517E7E031511187500D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = MemoryCachePruneWithinResourceLoadDelegate.html; sourceTree = "<group>"; };
+		51820A4C22F4EE7700DF0A01 /* _javascript_URLNavigation.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _javascript_URLNavigation.mm; sourceTree = "<group>"; };
 		5182C22D1F2BCB410059BA7C /* WKURLSchemeHandler-leaks.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "WKURLSchemeHandler-leaks.mm"; sourceTree = "<group>"; };
 		518C1152205B04F9001FF4AE /* ProcessSwapOnNavigation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ProcessSwapOnNavigation.mm; sourceTree = "<group>"; };
 		518EE51620A78CDF00E024F3 /* DoubleDefersLoading.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DoubleDefersLoading.mm; sourceTree = "<group>"; };
@@ -3776,6 +3778,7 @@
 				C507E8A614C6545B005D6B3B /* InspectorBar.mm */,
 				57F10D921C7E7B3800ECDF30 /* IsNavigationActionTrusted.mm */,
 				4BB4160116815B2600824238 /* JSWrapperForNodeInWebFrame.mm */,
+				51820A4C22F4EE7700DF0A01 /* _javascript_URLNavigation.mm */,
 				F4BFA68C1E4AD08000154298 /* LegacyDragAndDropTests.mm */,
 				7A7B0E7E1EAFE454006AB8AE /* LimitTitleSize.mm */,
 				57901FAE1CAF137100ED64F9 /* LoadInvalidURLRequest.mm */,
@@ -4706,6 +4709,7 @@
 				2EB242B821D4140B0055C1C0 /* UseSelectionAsFindString.mm in Sources */,
 				7C83E03A1D0A602700FEBCF3 /* UtilitiesCocoa.mm in Sources */,
 				7C83E0C61D0A654E00FEBCF3 /* VideoControlsManager.mm in Sources */,
+				51820A4D22F4EE7F00DF0A01 /* _javascript_URLNavigation.mm in Sources */,
 				CD3065E02165682E00E895DF /* VideoQualityDisplayCompositing.mm in Sources */,
 				115EB3431EE0BA03003C2C0A /* ViewportSizeForViewportUnits.mm in Sources */,
 				6356FB221EC4E0BA0044BF18 /* VisibleContentRect.mm in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/mac/_javascript_URLNavigation.mm (0 => 248410)


--- trunk/Tools/TestWebKitAPI/Tests/mac/_javascript_URLNavigation.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/mac/_javascript_URLNavigation.mm	2019-08-08 15:54:37 UTC (rev 248410)
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#if PLATFORM(MAC)
+
+#import "PlatformUtilities.h"
+#import "Test.h"
+#import "TestNavigationDelegate.h"
+#import "TestURLSchemeHandler.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKUIDelegatePrivate.h>
+#import <WebKit/WKURLSchemeHandler.h>
+#import <WebKit/WKURLSchemeTaskPrivate.h>
+#import <WebKit/WKWebViewConfigurationPrivate.h>
+#import <WebKit/WebKit.h>
+#import <wtf/BlockPtr.h>
+#import <wtf/HashMap.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/RunLoop.h>
+#import <wtf/Threading.h>
+#import <wtf/Vector.h>
+#import <wtf/text/StringHash.h>
+#import <wtf/text/WTFString.h>
+
+static RetainPtr<WKWebView> createdWebView;
+static RetainPtr<TestNavigationDelegate> navDelegate;
+
+@interface _javascript_URLNavigationDelegate : NSObject <WKUIDelegatePrivate>
+@end
+@implementation _javascript_URLNavigationDelegate
+
+- (void)_webViewRunModal:(WKWebView *)webView
+{
+    EXPECT_EQ(webView, createdWebView.get());
+}
+
+- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
+{
+    createdWebView = [[[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration] autorelease];
+    [createdWebView setUIDelegate:self];
+
+    navDelegate = adoptNS([[TestNavigationDelegate alloc] init]);
+    [navDelegate setDecidePolicyForNavigationAction:[&] (WKNavigationAction *action, void (^decisionHandler)(WKNavigationActionPolicy)) {
+        decisionHandler(WKNavigationActionPolicyAllow);
+    }];
+    [createdWebView setNavigationDelegate:navDelegate.get()];
+
+    return createdWebView.get();
+}
+
+- (void)_webViewClose:(WKWebView *)webView
+{
+    EXPECT_EQ(webView, createdWebView.get());
+    [webView _close];
+}
+
+@end
+
+static const char* mainResource = R"JSURLRESOURCE(
+<body>
+The initial frame should have "Hello there" in it.<br>
+The second frame should not.<br>
+<script>
+
+function createURL(data, type = 'text/html') {
+  return URL.createObjectURL(new Blob([data], {type: type}));
+}
+
+function waitForLoad() {
+    showModalDialog(createURL(`
+        <script>
+        var dataURLDelay = 400;
+        var earlyReturn = false;
+        function tryIt() {
+            if (earlyReturn)
+                return;
+            try {
+                opener.frame.contentDocument.x;
+            } catch (e) {
+                earlyReturn = true;
+                setTimeout(window.close, dataURLDelay * 1.5);
+            }
+        };
+        setTimeout(tryIt, dataURLDelay);
+        setTimeout(tryIt, dataURLDelay * 1.5);
+        setTimeout(tryIt, dataURLDelay * 2);
+        setTimeout(tryIt, dataURLDelay * 2.5);
+        setTimeout(window.close, dataURLDelay * 3);
+        </scrip` + 't>'
+    ));
+}
+
+function runTest() {
+    window._onmessage_ = null;
+
+    frame = document.createElement('iframe');
+    frame.src = ""
+    document.body.appendChild(frame);
+
+    frame.contentDocument.open();
+    frame.contentWindow.addEventListener('readystatechange', () => {
+        a = frame.contentDocument.createElement('a');
+        a.href = ""
+        a.click();
+        waitForLoad();
+    }, {capture: true, once: true});
+
+    var _javascript_Source = `
+    <script>
+    alert(document.documentElement.outerHTML);
+    function checkIt() {
+        if (document.documentElement.outerHTML.includes('Hello worl' + 'd')) {
+            console.log('Failed');
+            if (window.webkit.messageHandlers && window.webkit.messageHandlers.testHandler)
+                window.webkit.messageHandlers.testHandler.postMessage('Failed');
+        } else {
+            console.log('Passed');
+            if (window.webkit.messageHandlers && window.webkit.messageHandlers.testHandler)
+                window.webkit.messageHandlers.testHandler.postMessage('Passed');
+        }
+    }
+    setTimeout(checkIt, 0);
+    </scrip` + 't>';
+    frame.src = '' + _javascript_Source + '"';
+}
+window._onmessage_ = runTest;
+
+var targetSource = `
+<script>
+function writeIt() {
+    document.write('Hello world');
+    parent.postMessage('go', '` + window.location.origin + `');
+}
+setTimeout(writeIt, 400);
+</scrip` + 't>';
+
+targetURL = 'data:text/html,' + targetSource;
+loadedOnce = document.body.appendChild(document.createElement('iframe'));
+loadedOnce.src = ""
+</script>
+</body>
+)JSURLRESOURCE";
+
+
+TEST(WKWebView, _javascript_URLNavigation)
+{
+    static bool done;
+
+    auto delegate = adoptNS([[_javascript_URLNavigationDelegate alloc] init]);
+    auto handler = adoptNS([[TestURLSchemeHandler alloc] init]);
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [configuration setURLSchemeHandler:handler.get() forURLScheme:@"jsurl"];
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
+    [webView setUIDelegate:delegate.get()];
+
+    [webView performAfterReceivingMessage:@"Passed" action:^() {
+        done = true;
+    }];
+    [webView performAfterReceivingMessage:@"Failed" action:^() {
+        done = true;
+        FAIL();
+    }];
+
+    [handler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
+
+        if (![task.request.URL.absoluteString isEqualToString:@"jsurl://host1/main.html"]) {
+            // We only expect the URL above.
+            FAIL();
+        }
+
+        auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:0 textEncodingName:nil]);
+        [task didReceiveResponse:response.get()];
+        [task didReceiveData:[NSData dataWithBytes:mainResource length:strlen(mainResource)]];
+        [task didFinish];
+    }];
+
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"jsurl://host1/main.html"]]];
+
+    TestWebKitAPI::Util::run(&done);
+}
+
+#endif // PLATFORM(MAC)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to