JavaScript URLs execute in sandboxed iframes
https://bugs.webkit.org/show_bug.cgi?id=71599
Reviewed by Eric Seidel.
Source/WebCore:
This patch fixes the intentional regression I introduced earlier today
by moving the sandbox bits from SecurityOrigin to Document. In the
process, I renamed SecurityOrigin::createEmpty to
SecurityOrigin::createUnique to better align with HTML5 terminology.
* WebCore.exp.in:
* bindings/ScriptControllerBase.cpp:
(WebCore::ScriptController::canExecuteScripts):
* dom/Document.cpp:
(WebCore::Document::setIsViewSource):
(WebCore::Document::initSecurityContext):
* dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContext::ScriptExecutionContext):
* dom/ScriptExecutionContext.h:
(WebCore::ScriptExecutionContext::sandboxFlags):
(WebCore::ScriptExecutionContext::enforceSandboxFlags):
(WebCore::ScriptExecutionContext::isSandboxed):
* html/HTMLAppletElement.cpp:
(WebCore::HTMLAppletElement::canEmbedJava):
* loader/DocumentWriter.cpp:
(WebCore::DocumentWriter::begin):
* loader/FrameLoader.cpp:
(WebCore::isDocumentSandboxed):
(WebCore::FrameLoader::addHTTPOriginIfNeeded):
* loader/PolicyChecker.cpp:
(WebCore::PolicyChecker::checkNewWindowPolicy):
* loader/SubframeLoader.cpp:
(WebCore::SubframeLoader::requestPlugin):
* page/SecurityOrigin.cpp:
(WebCore::SecurityOrigin::SecurityOrigin):
(WebCore::SecurityOrigin::create):
(WebCore::SecurityOrigin::createUnique):
* page/SecurityOrigin.h:
LayoutTests:
Update results to show progression.
* fast/frames/sandboxed-iframe-scripting-expected.txt:
* fast/frames/sandboxed-iframe-scripting.html:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@99347 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index db0941f..60e8c11 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
+2011-11-04 Adam Barth <abarth@webkit.org>
+
+ JavaScript URLs execute in sandboxed iframes
+ https://bugs.webkit.org/show_bug.cgi?id=71599
+
+ Reviewed by Eric Seidel.
+
+ Update results to show progression.
+
+ * fast/frames/sandboxed-iframe-scripting-expected.txt:
+ * fast/frames/sandboxed-iframe-scripting.html:
+
2011-11-04 Stephen Chenney <schenney@chromium.org>
Crash in ScrollAnimator.cpp
diff --git a/LayoutTests/fast/frames/sandboxed-iframe-scripting-expected.txt b/LayoutTests/fast/frames/sandboxed-iframe-scripting-expected.txt
index 0394b44..fd4dd39 100644
--- a/LayoutTests/fast/frames/sandboxed-iframe-scripting-expected.txt
+++ b/LayoutTests/fast/frames/sandboxed-iframe-scripting-expected.txt
@@ -4,7 +4,7 @@
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-FAIL disallowedExecuted should be 0. Was 1.
+PASS disallowedExecuted is 0
PASS allowedExecuted is 3
PASS successfullyParsed is true
diff --git a/LayoutTests/fast/frames/sandboxed-iframe-scripting.html b/LayoutTests/fast/frames/sandboxed-iframe-scripting.html
index 69877a0..cdb6570 100644
--- a/LayoutTests/fast/frames/sandboxed-iframe-scripting.html
+++ b/LayoutTests/fast/frames/sandboxed-iframe-scripting.html
@@ -26,10 +26,6 @@
<iframe sandbox="allow-same-origin allow-scripts"
src="data:text/html,<script> alert('PASS: Executed script in data URL'); </script>">
</iframe>
- <!-- This case execute script even though it shouldn't. The problem is that
- the iframe starts out as about:blank, which inherits the parent documents
- SecurityOrigin, along with its frozen sandbox bits. To fix this case,
- we'll need to move the sandbox bits from SecurityOrigin to Document. --!>
<iframe sandbox="allow-same-origin"
src="javascript: ++window.top.disallowedExecuted;">
</iframe>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index a97c722f..150c953 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,44 @@
+2011-11-04 Adam Barth <abarth@webkit.org>
+
+ JavaScript URLs execute in sandboxed iframes
+ https://bugs.webkit.org/show_bug.cgi?id=71599
+
+ Reviewed by Eric Seidel.
+
+ This patch fixes the intentional regression I introduced earlier today
+ by moving the sandbox bits from SecurityOrigin to Document. In the
+ process, I renamed SecurityOrigin::createEmpty to
+ SecurityOrigin::createUnique to better align with HTML5 terminology.
+
+ * WebCore.exp.in:
+ * bindings/ScriptControllerBase.cpp:
+ (WebCore::ScriptController::canExecuteScripts):
+ * dom/Document.cpp:
+ (WebCore::Document::setIsViewSource):
+ (WebCore::Document::initSecurityContext):
+ * dom/ScriptExecutionContext.cpp:
+ (WebCore::ScriptExecutionContext::ScriptExecutionContext):
+ * dom/ScriptExecutionContext.h:
+ (WebCore::ScriptExecutionContext::sandboxFlags):
+ (WebCore::ScriptExecutionContext::enforceSandboxFlags):
+ (WebCore::ScriptExecutionContext::isSandboxed):
+ * html/HTMLAppletElement.cpp:
+ (WebCore::HTMLAppletElement::canEmbedJava):
+ * loader/DocumentWriter.cpp:
+ (WebCore::DocumentWriter::begin):
+ * loader/FrameLoader.cpp:
+ (WebCore::isDocumentSandboxed):
+ (WebCore::FrameLoader::addHTTPOriginIfNeeded):
+ * loader/PolicyChecker.cpp:
+ (WebCore::PolicyChecker::checkNewWindowPolicy):
+ * loader/SubframeLoader.cpp:
+ (WebCore::SubframeLoader::requestPlugin):
+ * page/SecurityOrigin.cpp:
+ (WebCore::SecurityOrigin::SecurityOrigin):
+ (WebCore::SecurityOrigin::create):
+ (WebCore::SecurityOrigin::createUnique):
+ * page/SecurityOrigin.h:
+
2011-11-04 Joseph Pecoraro <pecoraro@apple.com>
Potential Unused Param Build Issue
diff --git a/Source/WebCore/WebCore.exp.in b/Source/WebCore/WebCore.exp.in
index 49951f0..1bbbbdb 100644
--- a/Source/WebCore/WebCore.exp.in
+++ b/Source/WebCore/WebCore.exp.in
@@ -390,7 +390,7 @@
__ZN7WebCore14SecurityOrigin32removeOriginAccessWhitelistEntryERKS0_RKN3WTF6StringES6_b
__ZN7WebCore14SecurityOrigin40setDomainRelaxationForbiddenForURLSchemeEbRKN3WTF6StringE
__ZN7WebCore14SecurityOrigin6createERKN3WTF6StringES4_i
-__ZN7WebCore14SecurityOrigin6createERKNS_4KURLEi
+__ZN7WebCore14SecurityOrigin6createERKNS_4KURLEb
__ZN7WebCore14StorageTracker7originsERN3WTF6VectorINS1_6RefPtrINS_14SecurityOriginEEELm0EEE
__ZN7WebCore14StorageTracker7trackerEv
__ZN7WebCore14StorageTracker9setClientEPNS_20StorageTrackerClientE
diff --git a/Source/WebCore/bindings/ScriptControllerBase.cpp b/Source/WebCore/bindings/ScriptControllerBase.cpp
index 63b976e..570f964 100644
--- a/Source/WebCore/bindings/ScriptControllerBase.cpp
+++ b/Source/WebCore/bindings/ScriptControllerBase.cpp
@@ -37,7 +37,7 @@
bool ScriptController::canExecuteScripts(ReasonForCallingCanExecuteScripts reason)
{
- if (m_frame->document() && m_frame->document()->securityOrigin()->isSandboxed(SandboxScripts))
+ if (m_frame->document() && m_frame->document()->isSandboxed(SandboxScripts))
return false;
if (m_frame->document() && m_frame->document()->isViewSource()) {
diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp
index ca989f19..948187d 100644
--- a/Source/WebCore/dom/Document.cpp
+++ b/Source/WebCore/dom/Document.cpp
@@ -1724,7 +1724,7 @@
if (!m_isViewSource)
return;
- ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::create(url(), SandboxOrigin));
+ ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::createUnique());
}
void Document::createStyleSelector()
@@ -4394,7 +4394,7 @@
// No source for a security context.
// This can occur via document.implementation.createDocument().
m_cookieURL = KURL(ParsedURLString, "");
- ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::createEmpty());
+ ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::createUnique());
ScriptExecutionContext::setContentSecurityPolicy(ContentSecurityPolicy::create(this));
return;
}
@@ -4402,7 +4402,8 @@
// In the common case, create the security context from the currently
// loading URL with a fresh content security policy.
m_cookieURL = m_url;
- ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::create(m_url, m_frame->loader()->sandboxFlags()));
+ ScriptExecutionContext::enforceSandboxFlags(m_frame->loader()->sandboxFlags());
+ ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::create(m_url, isSandboxed(SandboxOrigin)));
ScriptExecutionContext::setContentSecurityPolicy(ContentSecurityPolicy::create(this));
if (SecurityOrigin::allowSubstituteDataAccessToLocal()) {
diff --git a/Source/WebCore/dom/ScriptExecutionContext.cpp b/Source/WebCore/dom/ScriptExecutionContext.cpp
index 1452f5b..030e0aa 100644
--- a/Source/WebCore/dom/ScriptExecutionContext.cpp
+++ b/Source/WebCore/dom/ScriptExecutionContext.cpp
@@ -89,7 +89,8 @@
}
ScriptExecutionContext::ScriptExecutionContext()
- : m_iteratingActiveDOMObjects(false)
+ : m_sandboxFlags(SandboxNone)
+ , m_iteratingActiveDOMObjects(false)
, m_inDestructor(false)
, m_inDispatchErrorEvent(false)
#if ENABLE(SQL_DATABASE)
diff --git a/Source/WebCore/dom/ScriptExecutionContext.h b/Source/WebCore/dom/ScriptExecutionContext.h
index c39d4e7..1f6d00c 100644
--- a/Source/WebCore/dom/ScriptExecutionContext.h
+++ b/Source/WebCore/dom/ScriptExecutionContext.h
@@ -29,6 +29,7 @@
#include "ActiveDOMObject.h"
#include "ConsoleTypes.h"
+#include "FrameLoaderTypes.h"
#include "KURL.h"
#include <wtf/Forward.h>
#include <wtf/HashMap.h>
@@ -94,8 +95,12 @@
virtual void disableEval() = 0;
SecurityOrigin* securityOrigin() const { return m_securityOrigin.get(); }
+ SandboxFlags sandboxFlags() const { return m_sandboxFlags; }
ContentSecurityPolicy* contentSecurityPolicy() { return m_contentSecurityPolicy.get(); }
+ void enforceSandboxFlags(SandboxFlags mask) { m_sandboxFlags |= mask; }
+ bool isSandboxed(SandboxFlags mask) const { return m_sandboxFlags & mask; }
+
bool sanitizeScriptError(String& errorMessage, int& lineNumber, String& sourceURL);
void reportException(const String& errorMessage, int lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack>);
virtual void addMessage(MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack>) = 0;
@@ -201,6 +206,7 @@
void closeMessagePorts();
+ SandboxFlags m_sandboxFlags;
RefPtr<SecurityOrigin> m_securityOrigin;
RefPtr<ContentSecurityPolicy> m_contentSecurityPolicy;
diff --git a/Source/WebCore/html/HTMLAppletElement.cpp b/Source/WebCore/html/HTMLAppletElement.cpp
index 1ba3448..cf6cc84 100644
--- a/Source/WebCore/html/HTMLAppletElement.cpp
+++ b/Source/WebCore/html/HTMLAppletElement.cpp
@@ -164,7 +164,7 @@
bool HTMLAppletElement::canEmbedJava() const
{
- if (document()->securityOrigin()->isSandboxed(SandboxPlugins))
+ if (document()->isSandboxed(SandboxPlugins))
return false;
Settings* settings = document()->settings();
diff --git a/Source/WebCore/loader/DocumentWriter.cpp b/Source/WebCore/loader/DocumentWriter.cpp
index 478d479..e9c4f9a 100644
--- a/Source/WebCore/loader/DocumentWriter.cpp
+++ b/Source/WebCore/loader/DocumentWriter.cpp
@@ -119,7 +119,7 @@
// If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
// then replace the document with one whose parser will ignore the incoming data (bug 39323)
- if (document->isPluginDocument() && document->securityOrigin()->isSandboxed(SandboxPlugins))
+ if (document->isPluginDocument() && document->isSandboxed(SandboxPlugins))
document = SinkDocument::create(m_frame, url);
// FIXME: Do we need to consult the content security policy here about blocked plug-ins?
diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp
index 41379bb..28d4680 100644
--- a/Source/WebCore/loader/FrameLoader.cpp
+++ b/Source/WebCore/loader/FrameLoader.cpp
@@ -163,7 +163,7 @@
//
static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask)
{
- return frame->document() && frame->document()->securityOrigin()->isSandboxed(mask);
+ return frame->document() && frame->document()->isSandboxed(mask);
}
FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
@@ -2546,7 +2546,7 @@
if (origin.isEmpty()) {
// If we don't know what origin header to attach, we attach the value
// for an empty origin.
- request.setHTTPOrigin(SecurityOrigin::createEmpty()->toString());
+ request.setHTTPOrigin(SecurityOrigin::createUnique()->toString());
return;
}
diff --git a/Source/WebCore/loader/PolicyChecker.cpp b/Source/WebCore/loader/PolicyChecker.cpp
index fde8600..5b3416e 100644
--- a/Source/WebCore/loader/PolicyChecker.cpp
+++ b/Source/WebCore/loader/PolicyChecker.cpp
@@ -93,7 +93,7 @@
void PolicyChecker::checkNewWindowPolicy(const NavigationAction& action, NewWindowPolicyDecisionFunction function,
const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, void* argument)
{
- if (m_frame->document() && m_frame->document()->securityOrigin()->isSandboxed(SandboxPopups))
+ if (m_frame->document() && m_frame->document()->isSandboxed(SandboxPopups))
return continueAfterNavigationPolicy(PolicyIgnore);
m_callback.set(request, formState, frameName, action, function, argument);
diff --git a/Source/WebCore/loader/SubframeLoader.cpp b/Source/WebCore/loader/SubframeLoader.cpp
index 7f48b9d..e02b07b 100644
--- a/Source/WebCore/loader/SubframeLoader.cpp
+++ b/Source/WebCore/loader/SubframeLoader.cpp
@@ -112,7 +112,7 @@
return false;
if (m_frame->document()) {
- if (m_frame->document()->securityOrigin()->isSandboxed(SandboxPlugins))
+ if (m_frame->document()->isSandboxed(SandboxPlugins))
return false;
if (!m_frame->document()->contentSecurityPolicy()->allowObjectFromSource(url))
return false;
diff --git a/Source/WebCore/page/SecurityOrigin.cpp b/Source/WebCore/page/SecurityOrigin.cpp
index a53ec89..906b9e5 100644
--- a/Source/WebCore/page/SecurityOrigin.cpp
+++ b/Source/WebCore/page/SecurityOrigin.cpp
@@ -66,12 +66,11 @@
return schemes.contains(scheme);
}
-SecurityOrigin::SecurityOrigin(const KURL& url, SandboxFlags sandboxFlags)
- : m_sandboxFlags(sandboxFlags)
- , m_protocol(url.protocol().isNull() ? "" : url.protocol().lower())
+SecurityOrigin::SecurityOrigin(const KURL& url, bool forceUnique)
+ : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower())
, m_host(url.host().isNull() ? "" : url.host().lower())
, m_port(url.port())
- , m_isUnique(isSandboxed(SandboxOrigin) || SchemeRegistry::shouldTreatURLSchemeAsNoAccess(m_protocol))
+ , m_isUnique(forceUnique || SchemeRegistry::shouldTreatURLSchemeAsNoAccess(m_protocol))
, m_universalAccess(false)
, m_domainWasSetInDOM(false)
, m_enforceFilePathSeparation(false)
@@ -131,8 +130,7 @@
}
SecurityOrigin::SecurityOrigin(const SecurityOrigin* other)
- : m_sandboxFlags(other->m_sandboxFlags)
- , m_protocol(other->m_protocol.isolatedCopy())
+ : m_protocol(other->m_protocol.isolatedCopy())
, m_host(other->m_host.isolatedCopy())
, m_encodedHost(other->m_encodedHost.isolatedCopy())
, m_domain(other->m_domain.isolatedCopy())
@@ -152,16 +150,18 @@
return m_protocol.isEmpty();
}
-PassRefPtr<SecurityOrigin> SecurityOrigin::create(const KURL& url, SandboxFlags sandboxFlags)
+PassRefPtr<SecurityOrigin> SecurityOrigin::create(const KURL& url, bool forceUnique)
{
if (!url.isValid())
- return adoptRef(new SecurityOrigin(KURL(), sandboxFlags));
- return adoptRef(new SecurityOrigin(url, sandboxFlags));
+ return adoptRef(new SecurityOrigin(blankURL(), forceUnique));
+ return adoptRef(new SecurityOrigin(url, forceUnique));
}
-PassRefPtr<SecurityOrigin> SecurityOrigin::createEmpty()
+PassRefPtr<SecurityOrigin> SecurityOrigin::createUnique()
{
- return create(KURL());
+ RefPtr<SecurityOrigin> origin = create(KURL());
+ ASSERT(origin->isUnique());
+ return origin.release();
}
PassRefPtr<SecurityOrigin> SecurityOrigin::isolatedCopy()
@@ -478,7 +478,7 @@
PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const String& host, int port)
{
if (port < 0 || port > MaxAllowedPort)
- create(KURL());
+ createUnique();
String decodedHost = decodeURLEscapeSequences(host);
return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port)));
}
diff --git a/Source/WebCore/page/SecurityOrigin.h b/Source/WebCore/page/SecurityOrigin.h
index 564599e..59588cb 100644
--- a/Source/WebCore/page/SecurityOrigin.h
+++ b/Source/WebCore/page/SecurityOrigin.h
@@ -40,11 +40,12 @@
class SecurityOrigin : public ThreadSafeRefCounted<SecurityOrigin> {
public:
+ static PassRefPtr<SecurityOrigin> create(const KURL&, bool forceUnique = false);
+ static PassRefPtr<SecurityOrigin> createUnique();
+
static PassRefPtr<SecurityOrigin> createFromDatabaseIdentifier(const String&);
static PassRefPtr<SecurityOrigin> createFromString(const String&);
static PassRefPtr<SecurityOrigin> create(const String& protocol, const String& host, int port);
- static PassRefPtr<SecurityOrigin> create(const KURL&, SandboxFlags = SandboxNone);
- static PassRefPtr<SecurityOrigin> createEmpty();
// Create a deep copy of this SecurityOrigin. This method is useful
// when marshalling a SecurityOrigin to another thread.
@@ -114,9 +115,6 @@
// WARNING: This is an extremely powerful ability. Use with caution!
void grantUniversalAccess();
- bool isSandboxed(SandboxFlags mask) const { return m_sandboxFlags & mask; }
- SandboxFlags sandboxFlags() const { return m_sandboxFlags; }
-
bool canAccessDatabase() const { return !isUnique(); }
bool canAccessLocalStorage() const { return !isUnique(); }
bool canAccessCookies() const { return !isUnique(); }
@@ -198,7 +196,7 @@
static void resetOriginAccessWhitelists();
private:
- SecurityOrigin(const KURL&, SandboxFlags);
+ explicit SecurityOrigin(const KURL&, bool forceUnique);
explicit SecurityOrigin(const SecurityOrigin*);
// FIXME: Rename this function to something more semantic.
@@ -207,7 +205,6 @@
bool isAccessWhiteListed(const SecurityOrigin*) const;
bool isAccessToURLWhiteListed(const KURL&) const;
- SandboxFlags m_sandboxFlags;
String m_protocol;
String m_host;
mutable String m_encodedHost;