REGRESSION (r209608): Cross-origin plugin document opened in child window blocked...
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 May 2017 18:55:45 +0000 (18:55 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 18 May 2017 18:55:45 +0000 (18:55 +0000)
window CSP when object-src 'none' is set
https://bugs.webkit.org/show_bug.cgi?id=172038
<rdar://problem/32258262>

Reviewed by Andy Estes.

Source/WebCore:

Fixes an issue where a cross-origin plugin document opened in a child window would inherit
the Content Security Policy (CSP) of its opener. In particular, a cross-origin plugin
document opened in a child window would be blocked when the CSP of its opener disallows
plugins (e.g. object-source 'none').

Prior to r209608 a document opened in a child window never inherited the CSP from its opener
and a plugin document loaded in a subframe would unconditionally inherit the CSP from its
parent frame. So, a plugin document opened in a child window would be allowed to load
regardless of whether its opener had a CSP that prevented plugins. Following r209608 a
document opened in a child window would inherit its CSP from its opener if and only if it
would inherit the security origin from its opener (e.g. about:blank) or was a plugin
document. The latter condition makes plugin documents opened in a child window unconditionally
inherit the CSP from their opener and is the cause of this bug. It seems reasonable to exempt
cross-origin plugin documents opened in a child window from the CSP inheritance rule because
such documents cannot compromise the origin of their opener. Same-origin plugin documents
opened in a child window will continue to inherit the CSP from their opener because such
documents can compromise the origin of their opener.

Tests: http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window.html
       http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window.html
       http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window.html

* dom/Document.cpp:
(WebCore::Document::shouldInheritContentSecurityPolicyFromOwner): Added.
(WebCore::Document::initContentSecurityPolicy):
* dom/Document.h:

Tools:

Teach the test Netscape plugin to look for a URL that contains plugin-document-alert-and-notify-done.pl.
When it sees this URL it will show a JavaScript alert and call testRunner.notifyDone().

* DumpRenderTree/TestNetscapePlugIn/main.cpp:
(NPP_New):

LayoutTests:

Adds tests to ensure that a same-origin- and cross-origin- plugin document opened in a child
window inherit and do not inherit the CSP of its opener, respectively. Also adds a test to
ensure that an about:blank window inherits the CSP plugin policy of its opener.

* http/tests/plugins/resources/plugin-document-alert-and-notify-done.pl: Added.
* http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window-expected.txt: Added.
* http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window.html: Added.
* http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window-expected.txt: Added.
* http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window.html: Added.
* http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window-expected.txt: Added.
* http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window.html: Added.
* platform/ios/TestExpectations: Skip added tests as iOS does not support plugins.

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/plugins/resources/plugin-document-alert-and-notify-done.pl [new file with mode: 0755]
LayoutTests/http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window.html [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window.html [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window.html [new file with mode: 0644]
LayoutTests/platform/ios/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Tools/ChangeLog
Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp

index 4ab1d20..9902e5d 100644 (file)
@@ -1,3 +1,25 @@
+2017-05-18  Daniel Bates  <dabates@apple.com>
+
+        REGRESSION (r209608): Cross-origin plugin document opened in child window blocked by parent
+        window CSP when object-src 'none' is set
+        https://bugs.webkit.org/show_bug.cgi?id=172038
+        <rdar://problem/32258262>
+
+        Reviewed by Andy Estes.
+
+        Adds tests to ensure that a same-origin- and cross-origin- plugin document opened in a child
+        window inherit and do not inherit the CSP of its opener, respectively. Also adds a test to
+        ensure that an about:blank window inherits the CSP plugin policy of its opener.
+
+        * http/tests/plugins/resources/plugin-document-alert-and-notify-done.pl: Added.
+        * http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window-expected.txt: Added.
+        * http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window.html: Added.
+        * http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window-expected.txt: Added.
+        * http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window.html: Added.
+        * http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window-expected.txt: Added.
+        * http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window.html: Added.
+        * platform/ios/TestExpectations: Skip added tests as iOS does not support plugins.
+
 2017-05-18  Keith Miller  <keith_miller@apple.com>
 
         WebAssembly API: test with neutered inputs
diff --git a/LayoutTests/http/tests/plugins/resources/plugin-document-alert-and-notify-done.pl b/LayoutTests/http/tests/plugins/resources/plugin-document-alert-and-notify-done.pl
new file mode 100755 (executable)
index 0000000..d6cc9cc
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/perl -wT
+use strict;
+
+# Do not rename this file. The TestNetscapePlugin is hardcoded to look for this filename
+# to trigger a JavaScript alert and call testRunner.notifyDone().
+print "Content-Type: application/x-webkit-test-netscape\n\n";
+print "This is a mock plugin. It alerts when loaded and calls testRunner.notifyDone()";
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window-expected.txt b/LayoutTests/http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window-expected.txt
new file mode 100644 (file)
index 0000000..3bd6482
--- /dev/null
@@ -0,0 +1,2 @@
+ALERT: Plugin Loaded!
+
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window.html b/LayoutTests/http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window.html
new file mode 100644 (file)
index 0000000..8e7a866
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; object-src 'none'">
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.setCanOpenWindows();
+    testRunner.setCloseRemainingWindowsWhenComplete(true);
+    testRunner.waitUntilDone();
+}
+</script>
+</head>
+<body>
+<script>
+window.open("http://localhost:8000/plugins/resources/plugin-document-alert-and-notify-done.pl");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window-expected.txt b/LayoutTests/http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window-expected.txt
new file mode 100644 (file)
index 0000000..bfb2780
--- /dev/null
@@ -0,0 +1,2 @@
+CONSOLE MESSAGE: Refused to load data:application/x-webkit-test-netscape,alertwhenloaded because it does not appear in the object-src directive of the Content Security Policy.
+
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window.html b/LayoutTests/http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window.html
new file mode 100644 (file)
index 0000000..ebb26c5
--- /dev/null
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; object-src 'none'">
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.setCanOpenWindows();
+    testRunner.setCloseRemainingWindowsWhenComplete(true);
+    testRunner.waitUntilDone();
+}
+</script>
+</head>
+<body>
+<pre id="console"></pre>
+<script>
+var childWindow = window.open("about:blank");
+var markup = [
+    '<object data="data:application/x-webkit-test-netscape,alertwhenloaded"></object>',
+    '<script>',
+    'function done()',
+    '{',
+    '    if (window.testRunner)',
+    '        testRunner.notifyDone();',
+    '}',
+    'window.setTimeout(done, 500);',
+    '<' + '/script>',
+]
+childWindow.document.write(markup.join("\n"));
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window-expected.txt b/LayoutTests/http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window-expected.txt
new file mode 100644 (file)
index 0000000..1c32e85
--- /dev/null
@@ -0,0 +1,2 @@
+CONSOLE MESSAGE: Refused to load http://127.0.0.1:8000/plugins/resources/plugin-document-alert-and-notify-done.pl because it does not appear in the object-src directive of the Content Security Policy.
+
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window.html b/LayoutTests/http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window.html
new file mode 100644 (file)
index 0000000..38c7ad1
--- /dev/null
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; object-src 'none'">
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.setCanOpenWindows();
+    testRunner.setCloseRemainingWindowsWhenComplete(true);
+    testRunner.waitUntilDone();
+}
+</script>
+</head>
+<body>
+<script>
+checkDidLoadAndNotifyDone(window.open("http://127.0.0.1:8000/plugins/resources/plugin-document-alert-and-notify-done.pl"));
+
+// Assumes that the specified window is loading a same-origin document.
+function checkDidLoadAndNotifyDone(childWindow)
+{
+    function checkDidLoad() {
+        if (childWindow.document.location.origin !== document.location.origin)
+            return;
+        // Child window did load
+        window.clearInterval(intervalID);
+        if (window.testRunner)
+            testRunner.notifyDone();
+    }
+    intervalID = window.setInterval(checkDidLoad, 10);
+}
+</script>
+</body>
+</html>
index dc43580..4b6582a 100644 (file)
@@ -126,6 +126,9 @@ http/tests/security/contentSecurityPolicy/object-with-no-url-allowed-by-default-
 http/tests/security/contentSecurityPolicy/object-with-no-url-allowed-by-star.html
 http/tests/security/contentSecurityPolicy/block-all-mixed-content/insecure-plugin-in-iframe.html
 http/tests/security/contentSecurityPolicy/block-all-mixed-content/insecure-plugin-in-main-frame.html
+http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window.html
+http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window.html
+http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window.html
 
 # Pointer-lock not supported on iOS
 pointer-lock
index 308bfb9..fffd419 100644 (file)
@@ -1,3 +1,39 @@
+2017-05-18  Daniel Bates  <dabates@apple.com>
+
+        REGRESSION (r209608): Cross-origin plugin document opened in child window blocked by parent
+        window CSP when object-src 'none' is set
+        https://bugs.webkit.org/show_bug.cgi?id=172038
+        <rdar://problem/32258262>
+
+        Reviewed by Andy Estes.
+
+        Fixes an issue where a cross-origin plugin document opened in a child window would inherit
+        the Content Security Policy (CSP) of its opener. In particular, a cross-origin plugin
+        document opened in a child window would be blocked when the CSP of its opener disallows
+        plugins (e.g. object-source 'none').
+
+        Prior to r209608 a document opened in a child window never inherited the CSP from its opener
+        and a plugin document loaded in a subframe would unconditionally inherit the CSP from its
+        parent frame. So, a plugin document opened in a child window would be allowed to load
+        regardless of whether its opener had a CSP that prevented plugins. Following r209608 a
+        document opened in a child window would inherit its CSP from its opener if and only if it
+        would inherit the security origin from its opener (e.g. about:blank) or was a plugin
+        document. The latter condition makes plugin documents opened in a child window unconditionally
+        inherit the CSP from their opener and is the cause of this bug. It seems reasonable to exempt
+        cross-origin plugin documents opened in a child window from the CSP inheritance rule because
+        such documents cannot compromise the origin of their opener. Same-origin plugin documents
+        opened in a child window will continue to inherit the CSP from their opener because such
+        documents can compromise the origin of their opener.
+
+        Tests: http/tests/security/contentSecurityPolicy/cross-origin-plugin-document-allowed-in-child-window.html
+               http/tests/security/contentSecurityPolicy/plugin-blocked-in-about-blank-window.html
+               http/tests/security/contentSecurityPolicy/same-origin-plugin-document-blocked-in-child-window.html
+
+        * dom/Document.cpp:
+        (WebCore::Document::shouldInheritContentSecurityPolicyFromOwner): Added.
+        (WebCore::Document::initContentSecurityPolicy):
+        * dom/Document.h:
+
 2017-05-18  Keith Miller  <keith_miller@apple.com>
 
         WebAssembly API: test with neutered inputs
index 2261ce6..1a83087 100644 (file)
@@ -5213,15 +5213,31 @@ void Document::initSecurityContext()
     setSecurityOriginPolicy(ownerFrame->document()->securityOriginPolicy());
 }
 
+bool Document::shouldInheritContentSecurityPolicyFromOwner() const
+{
+    ASSERT(m_frame);
+    if (shouldInheritSecurityOriginFromOwner(m_url))
+        return true;
+    if (!isPluginDocument())
+        return false;
+    if (m_frame->tree().parent())
+        return true;
+    Frame* openerFrame = m_frame->loader().opener();
+    if (!openerFrame)
+        return false;
+    return openerFrame->document()->securityOrigin().canAccess(securityOrigin());
+}
+
 void Document::initContentSecurityPolicy()
 {
+    // 1. Inherit Upgrade Insecure Requests
     Frame* parentFrame = m_frame->tree().parent();
     if (parentFrame)
         contentSecurityPolicy()->copyUpgradeInsecureRequestStateFrom(*parentFrame->document()->contentSecurityPolicy());
 
-    if (!shouldInheritSecurityOriginFromOwner(m_url) && !isPluginDocument())
+    // 2. Inherit Content Security Policy
+    if (!shouldInheritContentSecurityPolicyFromOwner())
         return;
-
     Frame* ownerFrame = parentFrame;
     if (!ownerFrame)
         ownerFrame = m_frame->loader().opener();
index 53cf679..6d3bb69 100644 (file)
@@ -1326,6 +1326,8 @@ private:
     friend class IgnoreDestructiveWriteCountIncrementer;
     friend class IgnoreOpensDuringUnloadCountIncrementer;
 
+    bool shouldInheritContentSecurityPolicyFromOwner() const;
+
     void detachFromFrame() { observeFrame(nullptr); }
 
     void updateTitleElement(Element* newTitleElement);
index 797dec5..0917a55 100644 (file)
@@ -1,3 +1,18 @@
+2017-05-18  Daniel Bates  <dabates@apple.com>
+
+        REGRESSION (r209608): Cross-origin plugin document opened in child window blocked by parent
+        window CSP when object-src 'none' is set
+        https://bugs.webkit.org/show_bug.cgi?id=172038
+        <rdar://problem/32258262>
+
+        Reviewed by Andy Estes.
+
+        Teach the test Netscape plugin to look for a URL that contains plugin-document-alert-and-notify-done.pl.
+        When it sees this URL it will show a JavaScript alert and call testRunner.notifyDone().
+
+        * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+        (NPP_New):
+
 2017-05-18  Per Arne Vollan  <pvollan@apple.com>
 
         [Win] Many layout tests are failing.
index 6a7303f..ca9cec8 100644 (file)
@@ -264,6 +264,8 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc
 #endif
         } else if (!strcasecmp(argn[i], "src") && strstr(argv[i], "plugin-document-has-focus.pl"))
             obj->testKeyboardFocusForPlugins = TRUE;
+        else if (!strcasecmp(argn[i], "src") && strstr(argv[i], "plugin-document-alert-and-notify-done.pl"))
+            executeScript(obj, "alert('Plugin Loaded!'); testRunner.notifyDone();");
         else if (!strcasecmp(argn[i], "evaluatescript")) {
             char* script = argv[i];
             if (script == strstr(script, "mouse::")) {