Make SecurityOrigin safe to create and use from any thread
https://bugs.webkit.org/show_bug.cgi?id=184216
Reviewed by Youenn Fablet.
We found that we have a decent amount of code constructing and using SecurityOrigin
objects from non-main threads. Unfortunately, this was not safe, mostly due to
SecurityOrigin's reliance on the SchemeRegistry.
This patch makes it safe to construct a SecurityOrigin on any thread A and use
it later on the same thread A. However, developers still need to call isolatedCopy()
if they want to pass such object to another thread B.
* page/SecurityOrigin.cpp:
(WebCore::SecurityOrigin::canDisplay const):
* page/SecurityOrigin.h:
* page/SecurityPolicy.cpp:
(WebCore::originAccessMapLock):
(WebCore::originAccessMap):
(WebCore::SecurityPolicy::isAccessWhiteListed):
(WebCore::SecurityPolicy::addOriginAccessWhitelistEntry):
(WebCore::SecurityPolicy::removeOriginAccessWhitelistEntry):
(WebCore::SecurityPolicy::resetOriginAccessWhitelists):
* platform/SchemeRegistry.cpp:
(WebCore::schemeRegistryLock):
(WebCore::allBuiltinSchemes):
(WebCore::builtinLocalURLSchemes):
(WebCore::localURLSchemes):
(WebCore::displayIsolatedURLSchemes):
(WebCore::builtinSecureSchemes):
(WebCore::secureSchemes):
(WebCore::builtinSchemesWithUniqueOrigins):
(WebCore::schemesWithUniqueOrigins):
(WebCore::builtinEmptyDocumentSchemes):
(WebCore::emptyDocumentSchemes):
(WebCore::schemesForbiddenFromDomainRelaxation):
(WebCore::builtinCanDisplayOnlyIfCanRequestSchemes):
(WebCore::canDisplayOnlyIfCanRequestSchemes):
(WebCore::notAllowingJavascriptURLsSchemes):
(WebCore::SchemeRegistry::registerURLSchemeAsLocal):
(WebCore::SchemeRegistry::removeURLSchemeRegisteredAsLocal):
(WebCore::schemesAllowingLocalStorageAccessInPrivateBrowsing):
(WebCore::schemesAllowingDatabaseAccessInPrivateBrowsing):
(WebCore::builtinCORSEnabledSchemes):
(WebCore::CORSEnabledSchemes):
(WebCore::ContentSecurityPolicyBypassingSchemes):
(WebCore::cachePartitioningSchemes):
(WebCore::serviceWorkerSchemes):
(WebCore::alwaysRevalidatedSchemes):
(WebCore::SchemeRegistry::shouldTreatURLSchemeAsLocal):
(WebCore::SchemeRegistry::registerURLSchemeAsNoAccess):
(WebCore::SchemeRegistry::shouldTreatURLSchemeAsNoAccess):
(WebCore::SchemeRegistry::registerURLSchemeAsDisplayIsolated):
(WebCore::SchemeRegistry::shouldTreatURLSchemeAsDisplayIsolated):
(WebCore::SchemeRegistry::registerURLSchemeAsSecure):
(WebCore::SchemeRegistry::shouldTreatURLSchemeAsSecure):
(WebCore::SchemeRegistry::canDisplayOnlyIfCanRequest):
(WebCore::SchemeRegistry::registerAsCanDisplayOnlyIfCanRequest):
(WebCore::SchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy):
(WebCore::SchemeRegistry::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy):
(WebCore::SchemeRegistry::schemeShouldBypassContentSecurityPolicy):
(WebCore::SchemeRegistry::registerURLSchemeAsCachePartitioned):
(WebCore::SchemeRegistry::shouldPartitionCacheForURLScheme):
(WebCore::SchemeRegistry::registerURLSchemeServiceWorkersCanHandle):
(WebCore::SchemeRegistry::canServiceWorkersHandleURLScheme):
(WebCore::SchemeRegistry::isServiceWorkerContainerCustomScheme):
* platform/SchemeRegistry.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@230205 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/platform/SchemeRegistry.cpp b/Source/WebCore/platform/SchemeRegistry.cpp
index 7e4d613..53dc195 100644
--- a/Source/WebCore/platform/SchemeRegistry.cpp
+++ b/Source/WebCore/platform/SchemeRegistry.cpp
@@ -65,6 +65,12 @@
return set;
}
+static Lock& schemeRegistryLock()
+{
+ static NeverDestroyed<Lock> lock;
+ return lock;
+}
+
static const URLSchemesMap& allBuiltinSchemes()
{
static const auto schemes = makeNeverDestroyed([] {
@@ -91,10 +97,14 @@
};
URLSchemesMap set;
- for (auto& scheme : builtinLocalURLSchemes())
- set.add(scheme);
- for (auto& function : functions)
- add(set, function);
+ {
+ Locker<Lock> locker(schemeRegistryLock());
+ for (auto& scheme : builtinLocalURLSchemes())
+ set.add(scheme);
+
+ for (auto& function : functions)
+ add(set, function);
+ }
for (auto& scheme : otherSchemes)
set.add(scheme);
return set;
@@ -104,6 +114,7 @@
static const URLSchemesMap& builtinLocalURLSchemes()
{
+ ASSERT(schemeRegistryLock().isHeld());
static const auto schemes = makeNeverDestroyed(URLSchemesMap {
"file",
#if PLATFORM(COCOA)
@@ -113,27 +124,23 @@
return schemes;
}
-static Lock& localURLSchemesLock()
-{
- static NeverDestroyed<Lock> lock;
- return lock;
-}
-
static URLSchemesMap& localURLSchemes()
{
- ASSERT(localURLSchemesLock().isHeld());
+ ASSERT(schemeRegistryLock().isHeld());
static NeverDestroyed<URLSchemesMap> localSchemes = builtinLocalURLSchemes();
return localSchemes;
}
static URLSchemesMap& displayIsolatedURLSchemes()
{
+ ASSERT(schemeRegistryLock().isHeld());
static NeverDestroyed<URLSchemesMap> displayIsolatedSchemes;
return displayIsolatedSchemes;
}
const Vector<String>& builtinSecureSchemes()
{
+ ASSERT(schemeRegistryLock().isHeld());
static const auto schemes = makeNeverDestroyed(Vector<String> {
"https",
"about",
@@ -146,21 +153,16 @@
return schemes;
}
-static Lock& secureSchemesLock()
-{
- static NeverDestroyed<Lock> lock;
- return lock;
-}
-
static URLSchemesMap& secureSchemes()
{
- ASSERT(secureSchemesLock().isHeld());
+ ASSERT(schemeRegistryLock().isHeld());
static auto secureSchemes = makeNeverDestroyedSchemeSet(builtinSecureSchemes);
return secureSchemes;
}
const Vector<String>& builtinSchemesWithUniqueOrigins()
{
+ ASSERT(schemeRegistryLock().isHeld());
static const auto schemes = makeNeverDestroyed(Vector<String> {
"about",
"javascript",
@@ -173,42 +175,49 @@
static URLSchemesMap& schemesWithUniqueOrigins()
{
+ ASSERT(schemeRegistryLock().isHeld());
static auto schemesWithUniqueOrigins = makeNeverDestroyedSchemeSet(builtinSchemesWithUniqueOrigins);
return schemesWithUniqueOrigins;
}
const Vector<String>& builtinEmptyDocumentSchemes()
{
+ ASSERT(isMainThread());
static const auto schemes = makeNeverDestroyed(Vector<String> { "about" });
return schemes;
}
static URLSchemesMap& emptyDocumentSchemes()
{
+ ASSERT(isMainThread());
static auto emptyDocumentSchemes = makeNeverDestroyedSchemeSet(builtinEmptyDocumentSchemes);
return emptyDocumentSchemes;
}
static URLSchemesMap& schemesForbiddenFromDomainRelaxation()
{
+ ASSERT(isMainThread());
static NeverDestroyed<URLSchemesMap> schemes;
return schemes;
}
const Vector<String>& builtinCanDisplayOnlyIfCanRequestSchemes()
{
+ ASSERT(schemeRegistryLock().isHeld());
static const auto schemes = makeNeverDestroyed(Vector<String> { "blob" });
return schemes;
}
static URLSchemesMap& canDisplayOnlyIfCanRequestSchemes()
{
+ ASSERT(schemeRegistryLock().isHeld());
static auto canDisplayOnlyIfCanRequestSchemes = makeNeverDestroyedSchemeSet(builtinCanDisplayOnlyIfCanRequestSchemes);
return canDisplayOnlyIfCanRequestSchemes;
}
static URLSchemesMap& notAllowingJavascriptURLsSchemes()
{
+ ASSERT(isMainThread());
static NeverDestroyed<URLSchemesMap> notAllowingJavascriptURLsSchemes;
return notAllowingJavascriptURLsSchemes;
}
@@ -218,13 +227,13 @@
if (scheme.isNull())
return;
- Locker<Lock> locker(localURLSchemesLock());
+ Locker<Lock> locker(schemeRegistryLock());
localURLSchemes().add(scheme);
}
void SchemeRegistry::removeURLSchemeRegisteredAsLocal(const String& scheme)
{
- Locker<Lock> locker(localURLSchemesLock());
+ Locker<Lock> locker(schemeRegistryLock());
if (builtinLocalURLSchemes().contains(scheme))
return;
@@ -233,24 +242,28 @@
static URLSchemesMap& schemesAllowingLocalStorageAccessInPrivateBrowsing()
{
+ ASSERT(isMainThread());
static NeverDestroyed<URLSchemesMap> schemesAllowingLocalStorageAccessInPrivateBrowsing;
return schemesAllowingLocalStorageAccessInPrivateBrowsing;
}
static URLSchemesMap& schemesAllowingDatabaseAccessInPrivateBrowsing()
{
+ ASSERT(isMainThread());
static NeverDestroyed<URLSchemesMap> schemesAllowingDatabaseAccessInPrivateBrowsing;
return schemesAllowingDatabaseAccessInPrivateBrowsing;
}
const Vector<String>& builtinCORSEnabledSchemes()
{
+ ASSERT(isMainThread());
static const auto schemes = makeNeverDestroyed(Vector<String> { "http", "https" });
return schemes;
}
static URLSchemesMap& CORSEnabledSchemes()
{
+ ASSERT(isMainThread());
// FIXME: http://bugs.webkit.org/show_bug.cgi?id=77160
static auto schemes = makeNeverDestroyedSchemeSet(builtinCORSEnabledSchemes);
return schemes;
@@ -258,31 +271,28 @@
static URLSchemesMap& ContentSecurityPolicyBypassingSchemes()
{
+ ASSERT(schemeRegistryLock().isHeld());
static NeverDestroyed<URLSchemesMap> schemes;
return schemes;
}
static URLSchemesMap& cachePartitioningSchemes()
{
+ ASSERT(schemeRegistryLock().isHeld());
static NeverDestroyed<URLSchemesMap> schemes;
return schemes;
}
-static Lock& serviceWorkerSchemesLock()
-{
- static NeverDestroyed<Lock> lock;
- return lock;
-}
-
static URLSchemesMap& serviceWorkerSchemes()
{
- ASSERT(serviceWorkerSchemesLock().isHeld());
+ ASSERT(schemeRegistryLock().isHeld());
static NeverDestroyed<URLSchemesMap> schemes;
return schemes;
}
static URLSchemesMap& alwaysRevalidatedSchemes()
{
+ ASSERT(isMainThread());
static NeverDestroyed<URLSchemesMap> schemes;
return schemes;
}
@@ -292,7 +302,7 @@
if (scheme.isNull())
return false;
- Locker<Lock> locker(localURLSchemesLock());
+ Locker<Lock> locker(schemeRegistryLock());
return localURLSchemes().contains(scheme);
}
@@ -300,24 +310,36 @@
{
if (scheme.isNull())
return;
+
+ Locker<Lock> locker(schemeRegistryLock());
schemesWithUniqueOrigins().add(scheme);
}
bool SchemeRegistry::shouldTreatURLSchemeAsNoAccess(const String& scheme)
{
- return !scheme.isNull() && schemesWithUniqueOrigins().contains(scheme);
+ if (scheme.isNull())
+ return false;
+
+ Locker<Lock> locker(schemeRegistryLock());
+ return schemesWithUniqueOrigins().contains(scheme);
}
void SchemeRegistry::registerURLSchemeAsDisplayIsolated(const String& scheme)
{
if (scheme.isNull())
return;
+
+ Locker<Lock> locker(schemeRegistryLock());
displayIsolatedURLSchemes().add(scheme);
}
bool SchemeRegistry::shouldTreatURLSchemeAsDisplayIsolated(const String& scheme)
{
- return !scheme.isNull() && displayIsolatedURLSchemes().contains(scheme);
+ if (scheme.isNull())
+ return false;
+
+ Locker<Lock> locker(schemeRegistryLock());
+ return displayIsolatedURLSchemes().contains(scheme);
}
void SchemeRegistry::registerURLSchemeAsSecure(const String& scheme)
@@ -325,7 +347,7 @@
if (scheme.isNull())
return;
- Locker<Lock> locker(secureSchemesLock());
+ Locker<Lock> locker(schemeRegistryLock());
secureSchemes().add(scheme);
}
@@ -334,7 +356,7 @@
if (scheme.isNull())
return false;
- Locker<Lock> locker(secureSchemesLock());
+ Locker<Lock> locker(schemeRegistryLock());
return secureSchemes().contains(scheme);
}
@@ -368,13 +390,19 @@
bool SchemeRegistry::canDisplayOnlyIfCanRequest(const String& scheme)
{
- return !scheme.isNull() && canDisplayOnlyIfCanRequestSchemes().contains(scheme);
+ if (scheme.isNull())
+ return false;
+
+ Locker<Lock> locker(schemeRegistryLock());
+ return canDisplayOnlyIfCanRequestSchemes().contains(scheme);
}
void SchemeRegistry::registerAsCanDisplayOnlyIfCanRequest(const String& scheme)
{
if (scheme.isNull())
return;
+
+ Locker<Lock> locker(schemeRegistryLock());
canDisplayOnlyIfCanRequestSchemes().add(scheme);
}
@@ -430,6 +458,8 @@
{
if (scheme.isNull())
return;
+
+ Locker<Lock> locker(schemeRegistryLock());
ContentSecurityPolicyBypassingSchemes().add(scheme);
}
@@ -437,12 +467,18 @@
{
if (scheme.isNull())
return;
+
+ Locker<Lock> locker(schemeRegistryLock());
ContentSecurityPolicyBypassingSchemes().remove(scheme);
}
bool SchemeRegistry::schemeShouldBypassContentSecurityPolicy(const String& scheme)
{
- return !scheme.isNull() && ContentSecurityPolicyBypassingSchemes().contains(scheme);
+ if (scheme.isNull())
+ return false;
+
+ Locker<Lock> locker(schemeRegistryLock());
+ return ContentSecurityPolicyBypassingSchemes().contains(scheme);
}
void SchemeRegistry::registerURLSchemeAsAlwaysRevalidated(const String& scheme)
@@ -461,12 +497,18 @@
{
if (scheme.isNull())
return;
+
+ Locker<Lock> locker(schemeRegistryLock());
cachePartitioningSchemes().add(scheme);
}
bool SchemeRegistry::shouldPartitionCacheForURLScheme(const String& scheme)
{
- return !scheme.isNull() && cachePartitioningSchemes().contains(scheme);
+ if (scheme.isNull())
+ return false;
+
+ Locker<Lock> locker(schemeRegistryLock());
+ return cachePartitioningSchemes().contains(scheme);
}
void SchemeRegistry::registerURLSchemeServiceWorkersCanHandle(const String& scheme)
@@ -474,7 +516,7 @@
if (scheme.isNull())
return;
- Locker<Lock> locker(serviceWorkerSchemesLock());
+ Locker<Lock> locker(schemeRegistryLock());
serviceWorkerSchemes().add(scheme);
}
@@ -490,13 +532,13 @@
return true;
}
- Locker<Lock> locker(serviceWorkerSchemesLock());
+ Locker<Lock> locker(schemeRegistryLock());
return serviceWorkerSchemes().contains(scheme);
}
bool SchemeRegistry::isServiceWorkerContainerCustomScheme(const String& scheme)
{
- Locker<Lock> locker(serviceWorkerSchemesLock());
+ Locker<Lock> locker(schemeRegistryLock());
return !scheme.isNull() && serviceWorkerSchemes().contains(scheme);
}