Can't use eval in iframes sanbdoxed via CSP header
authorabarth@webkit.org <abarth@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 9 Jun 2012 19:35:02 +0000 (19:35 +0000)
committerabarth@webkit.org <abarth@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 9 Jun 2012 19:35:02 +0000 (19:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=88450

Reviewed by Mihai Parparita.

Source/WebCore:

The initial empty document in a frame inherits the security context of
its parent (including the CSP policy).  When we load the real document,
in some cases we'll do a "secure transition" to the new document.  That
means that we leave the global object in place in case the parent
document has created any properties that it expects will be visible to
the new document.

If the parent document has a CSP policy that blocks eval, the "no eval"
bit will be set on the global object of the initial document.  When we
perform a "secure transition" to the new document, we'll keep the bit,
which is wrong.  In this patch, we reset the bit by always enabling
eval when clearing the context, regardless of whether we're performing
a "secure transition".

Test: http/tests/security/contentSecurityPolicy/iframe-inside-csp.html

* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::enableEval):
(WebCore):
* bindings/js/ScriptController.h:
(ScriptController):
* bindings/v8/ScriptController.cpp:
(WebCore::ScriptController::enableEval):
(WebCore):
(WebCore::ScriptController::disableEval):
* bindings/v8/ScriptController.h:
(ScriptController):
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::clear):

LayoutTests:

* http/tests/security/contentSecurityPolicy/iframe-inside-csp-expected.txt: Added.
* http/tests/security/contentSecurityPolicy/iframe-inside-csp.html: Added.
* http/tests/security/contentSecurityPolicy/resources/sandboxed-eval.php: Added.

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

LayoutTests/ChangeLog
LayoutTests/http/tests/security/contentSecurityPolicy/iframe-inside-csp-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/iframe-inside-csp.html [new file with mode: 0644]
LayoutTests/http/tests/security/contentSecurityPolicy/resources/sandboxed-eval.php [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/ScriptController.cpp
Source/WebCore/bindings/js/ScriptController.h
Source/WebCore/bindings/v8/ScriptController.cpp
Source/WebCore/bindings/v8/ScriptController.h
Source/WebCore/loader/FrameLoader.cpp

index d707121..bff38a9 100644 (file)
@@ -1,3 +1,14 @@
+2012-06-09  Adam Barth  <abarth@webkit.org>
+
+        Can't use eval in iframes sanbdoxed via CSP header
+        https://bugs.webkit.org/show_bug.cgi?id=88450
+
+        Reviewed by Mihai Parparita.
+
+        * http/tests/security/contentSecurityPolicy/iframe-inside-csp-expected.txt: Added.
+        * http/tests/security/contentSecurityPolicy/iframe-inside-csp.html: Added.
+        * http/tests/security/contentSecurityPolicy/resources/sandboxed-eval.php: Added.
+
 2012-06-09  Christophe Dumez  <christophe.dumez@intel.com>
 
         [EFL] skip new tests added in r119883
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/iframe-inside-csp-expected.txt b/LayoutTests/http/tests/security/contentSecurityPolicy/iframe-inside-csp-expected.txt
new file mode 100644 (file)
index 0000000..a86e993
--- /dev/null
@@ -0,0 +1,3 @@
+ALERT: PASS (1/2): Script can execute
+ALERT: PASS (2/2): Eval works
+
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/iframe-inside-csp.html b/LayoutTests/http/tests/security/contentSecurityPolicy/iframe-inside-csp.html
new file mode 100644 (file)
index 0000000..941a3dd
--- /dev/null
@@ -0,0 +1,3 @@
+<meta http-equiv="X-WebKit-CSP" content="script-src 'self'">
+<script src="resources/dump-as-text.js"></script>
+<iframe src="resources/sandboxed-eval.php"></iframe>
diff --git a/LayoutTests/http/tests/security/contentSecurityPolicy/resources/sandboxed-eval.php b/LayoutTests/http/tests/security/contentSecurityPolicy/resources/sandboxed-eval.php
new file mode 100644 (file)
index 0000000..7434f23
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+header("X-WebKit-CSP: sandbox allow-scripts");
+?>
+<script>
+alert('PASS (1/2): Script can execute');
+</script>
+<script>
+eval("alert('PASS (2/2): Eval works')");
+</script>
+Done.
index 033b831..257cf5a 100644 (file)
@@ -1,3 +1,40 @@
+2012-06-09  Adam Barth  <abarth@webkit.org>
+
+        Can't use eval in iframes sanbdoxed via CSP header
+        https://bugs.webkit.org/show_bug.cgi?id=88450
+
+        Reviewed by Mihai Parparita.
+
+        The initial empty document in a frame inherits the security context of
+        its parent (including the CSP policy).  When we load the real document,
+        in some cases we'll do a "secure transition" to the new document.  That
+        means that we leave the global object in place in case the parent
+        document has created any properties that it expects will be visible to
+        the new document.
+
+        If the parent document has a CSP policy that blocks eval, the "no eval"
+        bit will be set on the global object of the initial document.  When we
+        perform a "secure transition" to the new document, we'll keep the bit,
+        which is wrong.  In this patch, we reset the bit by always enabling
+        eval when clearing the context, regardless of whether we're performing
+        a "secure transition".
+
+        Test: http/tests/security/contentSecurityPolicy/iframe-inside-csp.html
+
+        * bindings/js/ScriptController.cpp:
+        (WebCore::ScriptController::enableEval):
+        (WebCore):
+        * bindings/js/ScriptController.h:
+        (ScriptController):
+        * bindings/v8/ScriptController.cpp:
+        (WebCore::ScriptController::enableEval):
+        (WebCore):
+        (WebCore::ScriptController::disableEval):
+        * bindings/v8/ScriptController.h:
+        (ScriptController):
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::clear):
+
 2012-06-09  Pablo Flouret  <pablof@motorola.com>
 
         The value in Access-Control-Allow-Origin is not being matched correctly for CORS-enabled requests
index fd80a46..7999502 100644 (file)
@@ -233,6 +233,14 @@ TextPosition ScriptController::eventHandlerPosition() const
     return TextPosition::minimumPosition();
 }
 
+void ScriptController::enableEval()
+{
+    JSDOMWindowShell* windowShell = existingWindowShell(mainThreadNormalWorld());
+    if (!windowShell)
+        return; // Eval is enabled by default.
+    windowShell->window()->setEvalEnabled(true);
+}
+
 void ScriptController::disableEval()
 {
     windowShell(mainThreadNormalWorld())->window()->setEvalEnabled(false);
index 9e8c28d..0ed9869 100644 (file)
@@ -104,6 +104,7 @@ public:
 
     WTF::TextPosition eventHandlerPosition() const;
 
+    void enableEval();
     void disableEval();
 
     static bool processingUserGesture();
index 42cda7a..c962e03 100644 (file)
@@ -279,13 +279,25 @@ bool ScriptController::haveInterpreter() const
     return m_proxy->windowShell()->isContextInitialized();
 }
 
+void ScriptController::enableEval()
+{
+    // We don't call initContextIfNeeded because contexts have eval enabled by default.
+
+    v8::HandleScope handleScope;
+    v8::Handle<v8::Context> v8Context = proxy()->windowShell()->context();
+    if (v8Context.IsEmpty())
+        return;
+
+    v8Context->AllowCodeGenerationFromStrings(true);
+}
+
 void ScriptController::disableEval()
 {
-    if (!m_proxy->windowShell()->initContextIfNeeded())
+    if (!proxy()->windowShell()->initContextIfNeeded())
         return;
 
     v8::HandleScope handleScope;
-    v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(m_frame);
+    v8::Handle<v8::Context> v8Context = proxy()->windowShell()->context();
     if (v8Context.IsEmpty())
         return;
 
index c71d284..41d71ce 100644 (file)
@@ -126,6 +126,7 @@ public:
     // Check if the javascript engine has been initialized.
     bool haveInterpreter() const;
 
+    void enableEval();
     void disableEval();
 
     static bool canAccessFromCurrentOrigin(Frame*);
index 2e50352..e46f9e1 100644 (file)
@@ -540,6 +540,8 @@ void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, boo
     if (clearScriptObjects)
         m_frame->script()->clearScriptObjects();
 
+    m_frame->script()->enableEval();
+
     m_frame->navigationScheduler()->clear();
 
     m_checkTimer.stop();