Index: Source/platform/weborigin/SecurityOrigin.cpp |
diff --git a/Source/platform/weborigin/SecurityOrigin.cpp b/Source/platform/weborigin/SecurityOrigin.cpp |
index b33955e0ec34ebf4481f60a5f19fd344f373f523..babd11cc59d2e611250828c068be3865ea5de26c 100644 |
--- a/Source/platform/weborigin/SecurityOrigin.cpp |
+++ b/Source/platform/weborigin/SecurityOrigin.cpp |
@@ -29,6 +29,7 @@ |
#include "config.h" |
#include "platform/weborigin/SecurityOrigin.h" |
+#include "platform/RuntimeEnabledFeatures.h" |
#include "platform/weborigin/KURL.h" |
#include "platform/weborigin/KnownPorts.h" |
#include "platform/weborigin/SchemeRegistry.h" |
@@ -37,6 +38,7 @@ |
#include "url/url_canon_ip.h" |
#include "wtf/HexNumber.h" |
#include "wtf/MainThread.h" |
+#include "wtf/NotFound.h" |
#include "wtf/StdLibExtras.h" |
#include "wtf/text/StringBuilder.h" |
@@ -62,6 +64,12 @@ static SecurityOrigin* cachedOrigin(const KURL& url) |
return 0; |
} |
+static bool sameSuborigin(const SecurityOrigin* origin1, const SecurityOrigin* origin2) |
+{ |
+ // If either origin has a suborigin set, both must have the same suborigin. |
+ return origin1->suboriginName() == origin2->suboriginName(); |
+} |
+ |
bool SecurityOrigin::shouldUseInnerURL(const KURL& url) |
{ |
// FIXME: Blob URLs don't have inner URLs. Their form is "blob:<inner-origin>/<UUID>", so treating the part after "blob:" as a URL is incorrect. |
@@ -116,6 +124,27 @@ static bool shouldTreatAsUniqueOrigin(const KURL& url) |
return false; |
} |
+bool deserializeSuboriginAndProtocol(const String& oldProtocol, String& suboriginName, String& newProtocol) |
+{ |
+ if (!RuntimeEnabledFeatures::suboriginsEnabled()) |
+ return false; |
+ |
+ const char suboriginPrefix[] = "suborigin+"; |
+ if (!oldProtocol.startsWith(suboriginPrefix)) |
+ return false; |
+ |
+ size_t suboriginStart = strlen(suboriginPrefix); |
+ size_t protocolStart = oldProtocol.find('+', suboriginStart + 1); |
+ |
+ if (protocolStart == kNotFound) |
+ return false; |
+ |
+ suboriginName = oldProtocol.substring(suboriginStart, protocolStart - suboriginStart); |
+ newProtocol = oldProtocol.substring(protocolStart + 1); |
+ |
+ return true; |
+} |
+ |
SecurityOrigin::SecurityOrigin(const KURL& url) |
: m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) |
, m_host(url.host().isNull() ? "" : url.host().lower()) |
@@ -126,6 +155,11 @@ SecurityOrigin::SecurityOrigin(const KURL& url) |
, m_enforceFilePathSeparation(false) |
, m_needsDatabaseIdentifierQuirkForFiles(false) |
{ |
+ // Suborigins are serialized into the protocol, so extract it if necessary. |
+ String suboriginName; |
+ if (deserializeSuboriginAndProtocol(m_protocol, suboriginName, m_protocol)) |
+ addSuborigin(suboriginName); |
+ |
// document.domain starts as m_host, but can be set by the DOM. |
m_domain = m_host; |
@@ -158,6 +192,7 @@ SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) |
, m_host(other->m_host.isolatedCopy()) |
, m_domain(other->m_domain.isolatedCopy()) |
, m_filePath(other->m_filePath.isolatedCopy()) |
+ , m_suboriginName(other->m_suboriginName) |
, m_port(other->m_port) |
, m_isUnique(other->m_isUnique) |
, m_universalAccess(other->m_universalAccess) |
@@ -200,6 +235,16 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createUnique() |
return origin.release(); |
} |
+void SecurityOrigin::addSuborigin(const String& suborigin) |
+{ |
+ ASSERT(RuntimeEnabledFeatures::suboriginsEnabled()); |
+ // Changing suborigins midstream is bad. Very bad. It should not happen. |
+ // This is, in fact, one of the very basic invariants that makes suborigins |
+ // an effective security tool. |
+ RELEASE_ASSERT(m_suboriginName.isNull() || m_suboriginName == suborigin); |
+ m_suboriginName = suborigin; |
+} |
+ |
PassRefPtr<SecurityOrigin> SecurityOrigin::isolatedCopy() const |
{ |
return adoptRef(new SecurityOrigin(this)); |
@@ -235,6 +280,9 @@ bool SecurityOrigin::canAccess(const SecurityOrigin* other) const |
if (isUnique() || other->isUnique()) |
return false; |
+ if (!sameSuborigin(this, other)) |
+ return false; |
+ |
// Here are two cases where we should permit access: |
// |
// 1) Neither document has set document.domain. In this case, we insist |
@@ -298,6 +346,9 @@ bool SecurityOrigin::canRequest(const KURL& url) const |
if (targetOrigin->isUnique()) |
return false; |
+ if (!sameSuborigin(this, targetOrigin.get())) |
+ return false; |
+ |
// We call isSameSchemeHostPort here instead of canAccess because we want |
// to ignore document.domain effects. |
if (isSameSchemeHostPort(targetOrigin.get())) |
@@ -392,6 +443,8 @@ SecurityOrigin::Policy SecurityOrigin::canShowNotifications() const |
return AlwaysAllow; |
if (isUnique()) |
return AlwaysDeny; |
+ if (hasSuborigin()) |
+ return AlwaysDeny; |
return Ask; |
} |
@@ -483,7 +536,14 @@ AtomicString SecurityOrigin::toRawAtomicString() const |
inline void SecurityOrigin::buildRawString(StringBuilder& builder) const |
{ |
- builder.reserveCapacity(m_protocol.length() + m_host.length() + 10); |
+ if (hasSuborigin()) { |
+ builder.reserveCapacity(11 + m_suboriginName.length() + m_protocol.length() + m_host.length() + 10); |
+ builder.appendLiteral("suborigin+"); |
+ builder.append(m_suboriginName); |
+ builder.append('+'); |
+ } else { |
+ builder.reserveCapacity(m_protocol.length() + m_host.length() + 10); |
+ } |
builder.append(m_protocol); |
builder.appendLiteral("://"); |
builder.append(m_host); |
@@ -509,6 +569,9 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const |
bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const |
{ |
+ if (!sameSuborigin(this, other)) |
+ return false; |
+ |
if (m_host != other->m_host) |
return false; |