mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1175138 P5 Make CacheStorage reject on untrusted origins. r=ehsan
This commit is contained in:
parent
a045d1505b
commit
3f01155885
@ -10495,9 +10495,17 @@ already_AddRefed<CacheStorage>
|
||||
nsGlobalWindow::GetCaches(ErrorResult& aRv)
|
||||
{
|
||||
if (!mCacheStorage) {
|
||||
bool forceTrustedOrigin = false;
|
||||
if (IsOuterWindow()) {
|
||||
forceTrustedOrigin = GetServiceWorkersTestingEnabled();
|
||||
} else {
|
||||
nsRefPtr<nsGlobalWindow> outer = GetOuterWindowInternal();
|
||||
forceTrustedOrigin = outer->GetServiceWorkersTestingEnabled();
|
||||
}
|
||||
mCacheStorage = CacheStorage::CreateOnMainThread(cache::DEFAULT_NAMESPACE,
|
||||
this, GetPrincipal(),
|
||||
IsPrivateBrowsing(), aRv);
|
||||
IsPrivateBrowsing(),
|
||||
forceTrustedOrigin, aRv);
|
||||
}
|
||||
|
||||
nsRefPtr<CacheStorage> ref = mCacheStorage;
|
||||
|
139
dom/cache/CacheStorage.cpp
vendored
139
dom/cache/CacheStorage.cpp
vendored
@ -25,6 +25,7 @@
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsURLParsers.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -62,11 +63,90 @@ struct CacheStorage::Entry final
|
||||
nsRefPtr<InternalRequest> mRequest;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
bool
|
||||
IsTrusted(const PrincipalInfo& aPrincipalInfo, bool aTestingPrefEnabled)
|
||||
{
|
||||
// Can happen on main thread or worker thread
|
||||
|
||||
if (aPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Require a ContentPrincipal to avoid null principal, etc.
|
||||
//
|
||||
// Also, an unknown appId means that this principal was created for the
|
||||
// codebase without all the security information from the end document or
|
||||
// worker. We require exact knowledge of this information before allowing
|
||||
// the caller to touch the disk using the Cache API.
|
||||
if (NS_WARN_IF(aPrincipalInfo.type() != PrincipalInfo::TContentPrincipalInfo ||
|
||||
aPrincipalInfo.get_ContentPrincipalInfo().appId() ==
|
||||
nsIScriptSecurityManager::UNKNOWN_APP_ID)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we're in testing mode, then don't do any more work to determing if
|
||||
// the origin is trusted. We have to run some tests as http.
|
||||
if (aTestingPrefEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now parse the scheme of the principal's origin. This is a short term
|
||||
// method for determining "trust". In the long term we need to implement
|
||||
// the full algorithm here:
|
||||
//
|
||||
// https://w3c.github.io/webappsec/specs/powerfulfeatures/#settings-secure
|
||||
//
|
||||
// TODO: Implement full secure setting algorithm. (bug 1177856)
|
||||
|
||||
const nsCString& flatURL = aPrincipalInfo.get_ContentPrincipalInfo().spec();
|
||||
const char* url = flatURL.get();
|
||||
|
||||
// off the main thread URL parsing using nsStdURLParser.
|
||||
nsCOMPtr<nsIURLParser> urlParser = new nsStdURLParser();
|
||||
|
||||
uint32_t schemePos;
|
||||
int32_t schemeLen;
|
||||
uint32_t authPos;
|
||||
int32_t authLen;
|
||||
nsresult rv = urlParser->ParseURL(url, flatURL.Length(),
|
||||
&schemePos, &schemeLen,
|
||||
&authPos, &authLen,
|
||||
nullptr, nullptr); // ignore path
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return false; }
|
||||
|
||||
nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
|
||||
if (scheme.LowerCaseEqualsLiteral("https") ||
|
||||
scheme.LowerCaseEqualsLiteral("app") ||
|
||||
scheme.LowerCaseEqualsLiteral("file")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t hostPos;
|
||||
int32_t hostLen;
|
||||
|
||||
rv = urlParser->ParseAuthority(url + authPos, authLen,
|
||||
nullptr, nullptr, // ignore username
|
||||
nullptr, nullptr, // ignore password
|
||||
&hostPos, &hostLen,
|
||||
nullptr); // ignore port
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return false; }
|
||||
|
||||
nsDependentCSubstring hostname(url + authPos + hostPos, hostLen);
|
||||
|
||||
return hostname.EqualsLiteral("localhost") ||
|
||||
hostname.EqualsLiteral("127.0.0.1") ||
|
||||
hostname.EqualsLiteral("::1");
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// static
|
||||
already_AddRefed<CacheStorage>
|
||||
CacheStorage::CreateOnMainThread(Namespace aNamespace, nsIGlobalObject* aGlobal,
|
||||
nsIPrincipal* aPrincipal, bool aPrivateBrowsing,
|
||||
ErrorResult& aRv)
|
||||
bool aForceTrustedOrigin, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aGlobal);
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
@ -78,38 +158,23 @@ CacheStorage::CreateOnMainThread(Namespace aNamespace, nsIGlobalObject* aGlobal,
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
bool nullPrincipal;
|
||||
nsresult rv = aPrincipal->GetIsNullPrincipal(&nullPrincipal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (nullPrincipal) {
|
||||
NS_WARNING("CacheStorage not supported on null principal.");
|
||||
nsRefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
// An unknown appId means that this principal was created for the codebase
|
||||
// without all the security information from the end document or worker.
|
||||
// We require exact knowledge of this information before allowing the
|
||||
// caller to touch the disk using the Cache API.
|
||||
bool unknownAppId = false;
|
||||
aPrincipal->GetUnknownAppId(&unknownAppId);
|
||||
if (unknownAppId) {
|
||||
NS_WARNING("CacheStorage not supported on principal with unknown appId.");
|
||||
nsRefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
PrincipalInfo principalInfo;
|
||||
rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
|
||||
nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool testingEnabled = aForceTrustedOrigin ||
|
||||
Preferences::GetBool("dom.caches.testing.enabled", false) ||
|
||||
Preferences::GetBool("dom.serviceWorkers.testing.enabled", false);
|
||||
|
||||
if (!IsTrusted(principalInfo, testingEnabled)) {
|
||||
NS_WARNING("CacheStorage not supported on untrusted origins.");
|
||||
nsRefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<CacheStorage> ref = new CacheStorage(aNamespace, aGlobal,
|
||||
principalInfo, nullptr);
|
||||
return ref.forget();
|
||||
@ -138,16 +203,13 @@ CacheStorage::CreateOnWorker(Namespace aNamespace, nsIGlobalObject* aGlobal,
|
||||
}
|
||||
|
||||
const PrincipalInfo& principalInfo = aWorkerPrivate->GetPrincipalInfo();
|
||||
if (principalInfo.type() == PrincipalInfo::TNullPrincipalInfo) {
|
||||
NS_WARNING("CacheStorage not supported on null principal.");
|
||||
nsRefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
if (principalInfo.type() == PrincipalInfo::TContentPrincipalInfo &&
|
||||
principalInfo.get_ContentPrincipalInfo().appId() ==
|
||||
nsIScriptSecurityManager::UNKNOWN_APP_ID) {
|
||||
NS_WARNING("CacheStorage not supported on principal with unknown appId.");
|
||||
bool testingEnabled = aWorkerPrivate->DOMCachesTestingEnabled() ||
|
||||
aWorkerPrivate->ServiceWorkersTestingEnabled() ||
|
||||
aWorkerPrivate->ServiceWorkersTestingInWindow();
|
||||
|
||||
if (!IsTrusted(principalInfo, testingEnabled)) {
|
||||
NS_WARNING("CacheStorage not supported on untrusted origins.");
|
||||
nsRefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return ref.forget();
|
||||
}
|
||||
@ -368,7 +430,10 @@ CacheStorage::Constructor(const GlobalObject& aGlobal,
|
||||
}
|
||||
}
|
||||
|
||||
return CreateOnMainThread(ns, global, aPrincipal, privateBrowsing, aRv);
|
||||
// Create a CacheStorage object bypassing the trusted origin checks
|
||||
// since this is a chrome-only constructor.
|
||||
return CreateOnMainThread(ns, global, aPrincipal, privateBrowsing,
|
||||
true /* force trusted origin */, aRv);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
|
2
dom/cache/CacheStorage.h
vendored
2
dom/cache/CacheStorage.h
vendored
@ -50,7 +50,7 @@ public:
|
||||
static already_AddRefed<CacheStorage>
|
||||
CreateOnMainThread(Namespace aNamespace, nsIGlobalObject* aGlobal,
|
||||
nsIPrincipal* aPrincipal, bool aPrivateBrowsing,
|
||||
ErrorResult& aRv);
|
||||
bool aForceTrustedOrigin, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<CacheStorage>
|
||||
CreateOnWorker(Namespace aNamespace, nsIGlobalObject* aGlobal,
|
||||
|
@ -1250,11 +1250,15 @@ CacheCreator::CreateCacheStorage(nsIPrincipal* aPrincipal)
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
// Create a CacheStorage bypassing its trusted origin checks. The
|
||||
// ServiceWorker has already performed its own checks before getting
|
||||
// to this point.
|
||||
ErrorResult error;
|
||||
mCacheStorage =
|
||||
CacheStorage::CreateOnMainThread(cache::CHROME_ONLY_NAMESPACE,
|
||||
mSandboxGlobalObject,
|
||||
aPrincipal, mPrivateBrowsing,
|
||||
true /* force trusted origin */,
|
||||
error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
|
@ -59,9 +59,15 @@ CreateCacheStorage(nsIPrincipal* aPrincipal, ErrorResult& aRv,
|
||||
// a service worker running in private browsing mode. Therefore if
|
||||
// we are purging scripts or running a comparison algorithm we cannot
|
||||
// be in private browing.
|
||||
//
|
||||
// Also, bypass the CacheStorage trusted origin checks. The ServiceWorker
|
||||
// has validated the origin prior to this point. All the information
|
||||
// to revalidate is not available now.
|
||||
return CacheStorage::CreateOnMainThread(cache::CHROME_ONLY_NAMESPACE,
|
||||
sandboxGlobalObject, aPrincipal,
|
||||
false /* private browsing */, aRv);
|
||||
false /* private browsing */,
|
||||
true /* force trusted origin */,
|
||||
aRv);
|
||||
}
|
||||
|
||||
class CompareManager;
|
||||
|
Loading…
Reference in New Issue
Block a user