Bug 1536411 - StoragePrincipal - part 8 - SharedWorkers, r=Ehsan

Differential Revision: https://phabricator.services.mozilla.com/D25790

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrea Marchesini 2019-04-11 16:47:26 +00:00
Родитель 677630aa7c
Коммит bba5a7d699
10 изменённых файлов: 139 добавлений и 41 удалений

Просмотреть файл

@ -465,13 +465,22 @@ already_AddRefed<BasePrincipal> BasePrincipal::CloneForcingFirstPartyDomain(
// XXX this is slow. Maybe we should consider to make it faster.
attrs.SetFirstPartyDomain(false, aURI, true /* aForced */);
return CloneForcingOriginAttributes(attrs);
}
already_AddRefed<BasePrincipal> BasePrincipal::CloneForcingOriginAttributes(
const OriginAttributes& aOriginAttributes) {
if (NS_WARN_IF(!IsCodebasePrincipal())) {
return nullptr;
}
nsAutoCString originNoSuffix;
nsresult rv = GetOriginNoSuffix(originNoSuffix);
NS_ENSURE_SUCCESS(rv, nullptr);
nsIURI* uri = static_cast<ContentPrincipal*>(this)->mCodebase;
RefPtr<ContentPrincipal> copy = new ContentPrincipal();
rv = copy->Init(uri, attrs, originNoSuffix);
rv = copy->Init(uri, aOriginAttributes, originNoSuffix);
NS_ENSURE_SUCCESS(rv, nullptr);
return copy.forget();

Просмотреть файл

@ -171,6 +171,9 @@ class BasePrincipal : public nsJSPrincipals {
already_AddRefed<BasePrincipal> CloneForcingFirstPartyDomain(nsIURI* aURI);
already_AddRefed<BasePrincipal> CloneForcingOriginAttributes(
const OriginAttributes& aOriginAttributes);
// If this is an add-on content script principal, returns its AddonPolicy.
// Otherwise returns null.
extensions::WebExtensionPolicy* ContentScriptAddonPolicy();

Просмотреть файл

@ -151,13 +151,10 @@ nsresult WorkerLoadInfo::GetPrincipalsAndLoadGroupFromChannel(
MOZ_DIAGNOSTIC_ASSERT(ssm);
nsCOMPtr<nsIPrincipal> channelPrincipal;
nsresult rv = ssm->GetChannelResultPrincipal(
aChannel, getter_AddRefs(channelPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrincipal> channelStoragePrincipal;
rv = ssm->GetChannelResultStoragePrincipal(
aChannel, getter_AddRefs(channelStoragePrincipal));
nsresult rv = ssm->GetChannelResultPrincipals(
aChannel, getter_AddRefs(channelPrincipal),
getter_AddRefs(channelStoragePrincipal));
NS_ENSURE_SUCCESS(rv, rv);
// Every time we call GetChannelResultPrincipal() it will return a different

Просмотреть файл

@ -102,14 +102,14 @@ already_AddRefed<SharedWorker> SharedWorker::Constructor(
do_QueryInterface(aGlobal.GetAsSupports());
MOZ_ASSERT(window);
// If the window is blocked from accessing storage, do not allow it
// to connect to a SharedWorker. This would potentially allow it
// to communicate with other windows that do have storage access.
// Allow private browsing, however, as we handle that isolation
// via the principal.
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
if (storageAllowed != nsContentUtils::StorageAccess::eAllow &&
storageAllowed != nsContentUtils::StorageAccess::ePrivateBrowsing) {
if (storageAllowed == nsContentUtils::StorageAccess::eDeny) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
if (storageAllowed == nsContentUtils::StorageAccess::ePartitionedOrDeny &&
!StaticPrefs::privacy_storagePrincipal_enabledForTrackers()) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
@ -176,6 +176,37 @@ already_AddRefed<SharedWorker> SharedWorker::Constructor(
return nullptr;
}
// Here, the StoragePrincipal is always equal to the SharedWorker's principal
// because the channel is not opened yet, and, because of this, it's not
// classified. We need to force the correct originAttributes.
if (storageAllowed == nsContentUtils::StorageAccess::ePartitionedOrDeny) {
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(window);
if (!sop) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsIPrincipal* windowPrincipal = sop->GetPrincipal();
if (!windowPrincipal) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsIPrincipal* windowStoragePrincipal = sop->GetEffectiveStoragePrincipal();
if (!windowStoragePrincipal) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
if (!windowPrincipal->Equals(windowStoragePrincipal)) {
loadInfo.mStoragePrincipal =
BasePrincipal::Cast(loadInfo.mPrincipal)
->CloneForcingOriginAttributes(
BasePrincipal::Cast(windowStoragePrincipal)
->OriginAttributesRef());
}
}
PrincipalInfo storagePrincipalInfo;
if (loadInfo.mPrincipal->Equals(loadInfo.mStoragePrincipal)) {
storagePrincipalInfo = principalInfo;

Просмотреть файл

@ -22,11 +22,13 @@ namespace dom {
// static
already_AddRefed<SharedWorkerManagerHolder> SharedWorkerManager::Create(
SharedWorkerService* aService, nsIEventTarget* aPBackgroundEventTarget,
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal) {
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal,
const OriginAttributes& aStoragePrincipalAttrs) {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<SharedWorkerManager> manager = new SharedWorkerManager(
aPBackgroundEventTarget, aData, aLoadingPrincipal);
RefPtr<SharedWorkerManager> manager =
new SharedWorkerManager(aPBackgroundEventTarget, aData, aLoadingPrincipal,
aStoragePrincipalAttrs);
RefPtr<SharedWorkerManagerHolder> holder =
new SharedWorkerManagerHolder(manager, aService);
@ -35,10 +37,12 @@ already_AddRefed<SharedWorkerManagerHolder> SharedWorkerManager::Create(
SharedWorkerManager::SharedWorkerManager(
nsIEventTarget* aPBackgroundEventTarget, const RemoteWorkerData& aData,
nsIPrincipal* aLoadingPrincipal)
nsIPrincipal* aLoadingPrincipal,
const OriginAttributes& aStoragePrincipalAttrs)
: mPBackgroundEventTarget(aPBackgroundEventTarget),
mLoadingPrincipal(aLoadingPrincipal),
mDomain(aData.domain()),
mStoragePrincipalAttrs(aStoragePrincipalAttrs),
mResolvedScriptURL(DeserializeURI(aData.resolvedScriptURL())),
mName(aData.name()),
mIsSecureContext(aData.isSecureContext()),
@ -80,11 +84,10 @@ bool SharedWorkerManager::MaybeCreateRemoteWorker(
}
already_AddRefed<SharedWorkerManagerHolder>
SharedWorkerManager::MatchOnMainThread(SharedWorkerService* aService,
const nsACString& aDomain,
nsIURI* aScriptURL,
const nsAString& aName,
nsIPrincipal* aLoadingPrincipal) {
SharedWorkerManager::MatchOnMainThread(
SharedWorkerService* aService, const nsACString& aDomain,
nsIURI* aScriptURL, const nsAString& aName, nsIPrincipal* aLoadingPrincipal,
const OriginAttributes& aStoragePrincipalAttrs) {
MOZ_ASSERT(NS_IsMainThread());
bool urlEquals;
@ -96,7 +99,8 @@ SharedWorkerManager::MatchOnMainThread(SharedWorkerService* aService,
// We want to be sure that the window's principal subsumes the
// SharedWorker's loading principal and vice versa.
mLoadingPrincipal->Subsumes(aLoadingPrincipal) &&
aLoadingPrincipal->Subsumes(mLoadingPrincipal);
aLoadingPrincipal->Subsumes(mLoadingPrincipal) &&
mStoragePrincipalAttrs == aStoragePrincipalAttrs;
if (!match) {
return nullptr;
}

Просмотреть файл

@ -67,14 +67,16 @@ class SharedWorkerManager final : public RemoteWorkerObserver {
static already_AddRefed<SharedWorkerManagerHolder> Create(
SharedWorkerService* aService, nsIEventTarget* aPBackgroundEventTarget,
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal);
const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal,
const OriginAttributes& aStoragePrincipalAttrs);
// Returns a holder if this manager matches. The holder blocks the shutdown of
// the manager.
already_AddRefed<SharedWorkerManagerHolder> MatchOnMainThread(
SharedWorkerService* aService, const nsACString& aDomain,
nsIURI* aScriptURL, const nsAString& aName,
nsIPrincipal* aLoadingPrincipal);
nsIPrincipal* aLoadingPrincipal,
const OriginAttributes& aStoragePrincipalAttrs);
// RemoteWorkerObserver
@ -114,7 +116,8 @@ class SharedWorkerManager final : public RemoteWorkerObserver {
private:
SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
const RemoteWorkerData& aData,
nsIPrincipal* aLoadingPrincipal);
nsIPrincipal* aLoadingPrincipal,
const OriginAttributes& aStoragePrincipalAttrs);
~SharedWorkerManager();
@ -122,6 +125,7 @@ class SharedWorkerManager final : public RemoteWorkerObserver {
nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
nsCString mDomain;
OriginAttributes mStoragePrincipalAttrs;
nsCOMPtr<nsIURI> mResolvedScriptURL;
nsString mName;
bool mIsSecureContext;

Просмотреть файл

@ -219,16 +219,9 @@ void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
MOZ_ASSERT(aActor);
nsresult rv = NS_OK;
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(aData.principalInfo(), &rv);
if (NS_WARN_IF(!principal)) {
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
return;
}
rv = PopulatePrincipalContentSecurityPolicy(principal, aData.principalCsp(),
aData.principalPreloadCsp());
if (NS_WARN_IF(NS_FAILED(rv))) {
nsCOMPtr<nsIPrincipal> storagePrincipal =
PrincipalInfoToPrincipal(aData.storagePrincipalInfo(), &rv);
if (NS_WARN_IF(!storagePrincipal)) {
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
return;
}
@ -255,8 +248,8 @@ void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
DeserializeURI(aData.resolvedScriptURL());
for (SharedWorkerManager* workerManager : mWorkerManagers) {
managerHolder = workerManager->MatchOnMainThread(
this, aData.domain(), resolvedScriptURL, aData.name(),
loadingPrincipal);
this, aData.domain(), resolvedScriptURL, aData.name(), loadingPrincipal,
BasePrincipal::Cast(storagePrincipal)->OriginAttributesRef());
if (managerHolder) {
break;
}
@ -264,8 +257,9 @@ void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
// Let's create a new one.
if (!managerHolder) {
managerHolder = SharedWorkerManager::Create(this, aBackgroundEventTarget,
aData, loadingPrincipal);
managerHolder = SharedWorkerManager::Create(
this, aBackgroundEventTarget, aData, loadingPrincipal,
BasePrincipal::Cast(storagePrincipal)->OriginAttributesRef());
mWorkerManagers.AppendElement(managerHolder->Manager());
} else {

Просмотреть файл

@ -98,3 +98,5 @@ support-files = cookies.sjs
[browser_partitionedDOMCache.js]
[browser_partitionedServiceWorkers.js]
support-files = matchAll.js
[browser_partitionedSharedWorkers.js]
support-files = sharedWorker.js

Просмотреть файл

@ -0,0 +1,36 @@
/* import-globals-from storageprincipal_head.js */
StoragePrincipalHelper.runTest("SharedWorkers",
async (win3rdParty, win1stParty, allowed) => {
let sh1 = new win1stParty.SharedWorker("sharedWorker.js");
await new Promise(resolve => {
sh1.port.onmessage = e => {
is(e.data, 1, "We expected 1 connection");
resolve();
};
sh1.port.postMessage("count");
});
let sh3 = new win3rdParty.SharedWorker("sharedWorker.js");
await new Promise(resolve => {
sh3.port.onmessage = e => {
ok(!allowed, "We should be here only if the SharedWorker is partitioned");
is(e.data, 1, "We expected 1 connection for 3rd party SharedWorker");
resolve();
};
sh3.onerror = _ => {
ok(allowed, "We should be here only if the SharedWorker is not partitioned");
resolve();
};
sh3.port.postMessage("count");
});
sh1.port.postMessage("close");
sh3.port.postMessage("close");
},
async _ => {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
});
});

Просмотреть файл

@ -0,0 +1,18 @@
let ports = 0;
self.onconnect = e => {
++ports;
e.ports[0].onmessage = event => {
if (event.data === "count") {
e.ports[0].postMessage(ports);
return;
}
if (event.data === "close") {
self.close();
return;
}
// Error.
e.ports[0].postMessage(-1);
};
};