diff --git a/browser/base/content/test/contextMenu/browser_contextmenu_loadblobinnewtab.js b/browser/base/content/test/contextMenu/browser_contextmenu_loadblobinnewtab.js index 4229e3a0d349..edbd64528d67 100644 --- a/browser/base/content/test/contextMenu/browser_contextmenu_loadblobinnewtab.js +++ b/browser/base/content/test/contextMenu/browser_contextmenu_loadblobinnewtab.js @@ -135,12 +135,6 @@ async function openInNewTabAndReturnContent(selector) { return blobDataFromContent; } -add_task(async function setup() { - await SpecialPowers.pushPrefEnv({ - set: [["privacy.partition.bloburl_per_agent_cluster", false]], - }); -}); - add_task(async function test_rightclick_open_bloburl_in_new_tab() { let blobDataFromLoadedPage = await rightClickOpenInNewTabAndReturnContent( "blob-url-link" diff --git a/dom/file/ipc/tests/browser_ipcBlob.js b/dom/file/ipc/tests/browser_ipcBlob.js index 3ba0f05c9039..ee99131d411e 100644 --- a/dom/file/ipc/tests/browser_ipcBlob.js +++ b/dom/file/ipc/tests/browser_ipcBlob.js @@ -4,12 +4,6 @@ requestLongerTimeout(3); const BASE_URI = "http://mochi.test:8888/browser/dom/file/ipc/tests/empty.html"; -add_task(async function setup() { - await SpecialPowers.pushPrefEnv({ - set: [["privacy.partition.bloburl_per_agent_cluster", false]], - }); -}); - // More than 1mb memory blob childA-parent-childB. add_task(async function test_CtoPtoC_big() { let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI); diff --git a/dom/file/tests/test_agentcluster_bloburl.js b/dom/file/tests/test_agentcluster_bloburl.js deleted file mode 100644 index cfb6013ab284..000000000000 --- a/dom/file/tests/test_agentcluster_bloburl.js +++ /dev/null @@ -1,166 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -const { CookieXPCShellUtils } = ChromeUtils.import( - "resource://testing-common/CookieXPCShellUtils.jsm" -); - -const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); - -CookieXPCShellUtils.init(this); - -// Same agent cluster, all works fine: blobURLs can be opened. -add_task(async () => { - do_get_profile(); - - Services.prefs.setBoolPref( - "privacy.partition.bloburl_per_agent_cluster", - true - ); - - const server = CookieXPCShellUtils.createServer({ hosts: ["example.org"] }); - - let result = new Promise(resolve => { - server.registerPathHandler("/result", (metadata, response) => { - resolve(metadata.queryString == "ok"); - - const body = "Done"; - response.bodyOutputStream.write(body, body.length); - }); - }); - - server.registerPathHandler("/test", (metadata, response) => { - response.setStatusLine(metadata.httpVersion, 200, "OK"); - response.setHeader("Content-Type", "text/html", false); - const body = ``; - response.bodyOutputStream.write(body, body.length); - }); - - let contentPage = await CookieXPCShellUtils.loadContentPage( - "http://example.org/test" - ); - - Assert.ok(await result, "BlobURL works"); - await contentPage.close(); -}); - -// Same agent cluster: frames -add_task(async () => { - do_get_profile(); - - const server = CookieXPCShellUtils.createServer({ hosts: ["example.org"] }); - - let result = new Promise(resolve => { - server.registerPathHandler("/result", (metadata, response) => { - resolve(metadata.queryString == "ok"); - - const body = "Done"; - response.bodyOutputStream.write(body, body.length); - }); - }); - - server.registerPathHandler("/iframe", (metadata, response) => { - response.setStatusLine(metadata.httpVersion, 200, "OK"); - response.setHeader("Content-Type", "text/html", false); - const body = ``; - response.bodyOutputStream.write(body, body.length); - }); - - server.registerPathHandler("/test", (metadata, response) => { - response.setStatusLine(metadata.httpVersion, 200, "OK"); - response.setHeader("Content-Type", "text/html", false); - const body = ``; - response.bodyOutputStream.write(body, body.length); - }); - - let contentPage = await CookieXPCShellUtils.loadContentPage( - "http://example.org/test" - ); - - Assert.ok(await result, "BlobURL works"); - await contentPage.close(); -}); - -// Cross agent cluster: different tabs -add_task(async () => { - do_get_profile(); - - const server = CookieXPCShellUtils.createServer({ hosts: ["example.org"] }); - - let result = new Promise(resolve => { - server.registerPathHandler("/result", (metadata, response) => { - resolve(metadata.queryString == "ok"); - - const body = "Done"; - response.bodyOutputStream.write(body, body.length); - }); - }); - - const step = new Promise(resolve => { - server.registerPathHandler("/step", (metadata, response) => { - resolve(metadata.queryString); - response.setStatusLine(metadata.httpVersion, 200, "OK"); - response.setHeader("Content-Type", "text/html", false); - const body = "Thanks!"; - response.bodyOutputStream.write(body, body.length); - }); - }); - - server.registerPathHandler("/test", (metadata, response) => { - response.setStatusLine(metadata.httpVersion, 200, "OK"); - response.setHeader("Content-Type", "text/html", false); - const body = ``; - response.bodyOutputStream.write(body, body.length); - }); - - let contentPage = await CookieXPCShellUtils.loadContentPage( - "http://example.org/test" - ); - - const blobURL = await step; - Assert.ok(blobURL.length, "We have a blobURL"); - - server.registerPathHandler("/cross-test", (metadata, response) => { - response.setStatusLine(metadata.httpVersion, 200, "OK"); - response.setHeader("Content-Type", "text/html", false); - const body = ``; - response.bodyOutputStream.write(body, body.length); - }); - - let contentPage2 = await CookieXPCShellUtils.loadContentPage( - "http://example.org/cross-test?" + blobURL - ); - - Assert.ok(!(await result), "BlobURL should not work"); - await contentPage.close(); - await contentPage2.close(); -}); diff --git a/dom/file/tests/xpcshell.ini b/dom/file/tests/xpcshell.ini index 978377cdc17a..dc9faecf8c45 100644 --- a/dom/file/tests/xpcshell.ini +++ b/dom/file/tests/xpcshell.ini @@ -4,4 +4,3 @@ [test_createFile.js] [test_ipc_messagemanager_blob.js] skip-if = os == "android" -[test_agentcluster_bloburl.js] diff --git a/dom/file/uri/BlobURLInputStream.cpp b/dom/file/uri/BlobURLInputStream.cpp index cff4ab51a616..eda701a9edab 100644 --- a/dom/file/uri/BlobURLInputStream.cpp +++ b/dom/file/uri/BlobURLInputStream.cpp @@ -363,25 +363,47 @@ void BlobURLInputStream::RetrieveBlobData(const MutexAutoLock& aProofOfLock) { return; } - Maybe agentClusterId; - Maybe clientInfo = loadInfo->GetClientInfo(); - if (clientInfo.isSome()) { - agentClusterId = clientInfo->AgentClusterId(); - } - if (XRE_IsParentProcess() || !BlobURLSchemeIsHTTPOrHTTPS(mBlobURLSpec)) { - RefPtr blobImpl; + nsIPrincipal* const dataEntryPrincipal = + BlobURLProtocolHandler::GetDataEntryPrincipal(mBlobURLSpec, + true /* AlsoIfRevoked */); // Since revoked blobs are also retrieved, it is possible that the blob no // longer exists (due to the 5 second timeout) when execution reaches here - if (!BlobURLProtocolHandler::GetDataEntry( - mBlobURLSpec, getter_AddRefs(blobImpl), loadingPrincipal, - triggeringPrincipal, loadInfo->GetOriginAttributes(), - agentClusterId, true /* AlsoIfRevoked */)) { + if (!dataEntryPrincipal) { NS_WARNING("Failed to get data entry principal. URL revoked?"); return; } + // We want to be sure that we stop the creation of the channel if the blob + // URL is copy-and-pasted on a different context (ex. private browsing or + // containers). + // + // We also allow the system principal to create the channel regardless of + // the OriginAttributes. This is primarily for the benefit of mechanisms + // like the Download API that explicitly create a channel with the system + // principal and which is never mutated to have a non-zero + // mPrivateBrowsingId or container. + if (NS_WARN_IF(!loadingPrincipal || + !loadingPrincipal->IsSystemPrincipal()) && + NS_WARN_IF(!ChromeUtils::IsOriginAttributesEqualIgnoringFPD( + loadInfo->GetOriginAttributes(), + BasePrincipal::Cast(dataEntryPrincipal)->OriginAttributesRef()))) { + return; + } + + if (NS_WARN_IF(!triggeringPrincipal->Subsumes(dataEntryPrincipal))) { + return; + } + + RefPtr blobImpl; + nsresult rv = NS_GetBlobForBlobURISpec( + mBlobURLSpec, getter_AddRefs(blobImpl), true /* AlsoIfRevoked */); + + if (NS_WARN_IF(NS_FAILED(rv)) || (NS_WARN_IF(!blobImpl))) { + return; + } + if (NS_WARN_IF( NS_FAILED(StoreBlobImplStream(blobImpl.forget(), aProofOfLock)))) { return; @@ -409,7 +431,7 @@ void BlobURLInputStream::RetrieveBlobData(const MutexAutoLock& aProofOfLock) { contentChild ->SendBlobURLDataRequest(mBlobURLSpec, triggeringPrincipal, loadingPrincipal, - loadInfo->GetOriginAttributes(), agentClusterId) + loadInfo->GetOriginAttributes()) ->Then( GetCurrentSerialEventTarget(), __func__, [self](const BlobURLDataRequestResult& aResult) { diff --git a/dom/file/uri/BlobURLProtocolHandler.cpp b/dom/file/uri/BlobURLProtocolHandler.cpp index 3e12804ce697..ae871d900e30 100644 --- a/dom/file/uri/BlobURLProtocolHandler.cpp +++ b/dom/file/uri/BlobURLProtocolHandler.cpp @@ -19,7 +19,6 @@ #include "mozilla/BasePrincipal.h" #include "mozilla/LoadInfo.h" #include "mozilla/NullPrincipal.h" -#include "mozilla/OriginAttributes.h" #include "mozilla/Preferences.h" #include "mozilla/SchedulerGroup.h" #include "nsClassHashtable.h" @@ -46,22 +45,18 @@ namespace dom { struct DataInfo { enum ObjectType { eBlobImpl, eMediaSource }; - DataInfo(BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId) + DataInfo(BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal) : mObjectType(eBlobImpl), mBlobImpl(aBlobImpl), mPrincipal(aPrincipal), - mAgentClusterId(aAgentClusterId), mRevoked(false) { MOZ_ASSERT(aPrincipal); } - DataInfo(MediaSource* aMediaSource, nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId) + DataInfo(MediaSource* aMediaSource, nsIPrincipal* aPrincipal) : mObjectType(eMediaSource), mMediaSource(aMediaSource), mPrincipal(aPrincipal), - mAgentClusterId(aAgentClusterId), mRevoked(false) { MOZ_ASSERT(aPrincipal); } @@ -72,8 +67,6 @@ struct DataInfo { RefPtr mMediaSource; nsCOMPtr mPrincipal; - Maybe mAgentClusterId; - nsCString mStack; // When a blobURL is revoked, we keep it alive for RELEASING_TIMER @@ -131,15 +124,14 @@ static DataInfo* GetDataInfoFromURI(nsIURI* aURI, bool aAlsoIfRevoked = false) { // Memory reporting for the hash table. void BroadcastBlobURLRegistration(const nsACString& aURI, BlobImpl* aBlobImpl, - nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId) { + nsIPrincipal* aPrincipal) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aBlobImpl); MOZ_ASSERT(aPrincipal); if (XRE_IsParentProcess()) { - dom::ContentParent::BroadcastBlobURLRegistration( - aURI, aBlobImpl, aPrincipal, aAgentClusterId); + dom::ContentParent::BroadcastBlobURLRegistration(aURI, aBlobImpl, + aPrincipal); return; } @@ -152,7 +144,7 @@ void BroadcastBlobURLRegistration(const nsACString& aURI, BlobImpl* aBlobImpl, } Unused << NS_WARN_IF(!cc->SendStoreAndBroadcastBlobURLRegistration( - nsCString(aURI), ipcBlob, IPC::Principal(aPrincipal), aAgentClusterId)); + nsCString(aURI), ipcBlob, IPC::Principal(aPrincipal))); } void BroadcastBlobURLUnregistration(const nsCString& aURI, @@ -518,15 +510,14 @@ NS_IMPL_ISUPPORTS_INHERITED(ReleasingTimerHolder, Runnable, nsITimerCallback, template static void AddDataEntryInternal(const nsACString& aURI, T aObject, - nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId) { + nsIPrincipal* aPrincipal) { MOZ_ASSERT(NS_IsMainThread(), "changing gDataTable is main-thread only"); StaticMutexAutoLock lock(sMutex); if (!gDataTable) { gDataTable = new nsClassHashtable; } - DataInfo* info = new DataInfo(aObject, aPrincipal, aAgentClusterId); + DataInfo* info = new DataInfo(aObject, aPrincipal); BlobURLsReporter::GetJSStackForBlob(info); gDataTable->Put(aURI, info); @@ -546,9 +537,9 @@ BlobURLProtocolHandler::BlobURLProtocolHandler() { Init(); } BlobURLProtocolHandler::~BlobURLProtocolHandler() = default; /* static */ -nsresult BlobURLProtocolHandler::AddDataEntry( - BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId, nsACString& aUri) { +nsresult BlobURLProtocolHandler::AddDataEntry(BlobImpl* aBlobImpl, + nsIPrincipal* aPrincipal, + nsACString& aUri) { MOZ_ASSERT(aBlobImpl); MOZ_ASSERT(aPrincipal); @@ -557,16 +548,16 @@ nsresult BlobURLProtocolHandler::AddDataEntry( nsresult rv = GenerateURIString(aPrincipal, aUri); NS_ENSURE_SUCCESS(rv, rv); - AddDataEntryInternal(aUri, aBlobImpl, aPrincipal, aAgentClusterId); + AddDataEntryInternal(aUri, aBlobImpl, aPrincipal); - BroadcastBlobURLRegistration(aUri, aBlobImpl, aPrincipal, aAgentClusterId); + BroadcastBlobURLRegistration(aUri, aBlobImpl, aPrincipal); return NS_OK; } /* static */ -nsresult BlobURLProtocolHandler::AddDataEntry( - MediaSource* aMediaSource, nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId, nsACString& aUri) { +nsresult BlobURLProtocolHandler::AddDataEntry(MediaSource* aMediaSource, + nsIPrincipal* aPrincipal, + nsACString& aUri) { MOZ_ASSERT(aMediaSource); MOZ_ASSERT(aPrincipal); @@ -575,24 +566,23 @@ nsresult BlobURLProtocolHandler::AddDataEntry( nsresult rv = GenerateURIString(aPrincipal, aUri); NS_ENSURE_SUCCESS(rv, rv); - AddDataEntryInternal(aUri, aMediaSource, aPrincipal, aAgentClusterId); + AddDataEntryInternal(aUri, aMediaSource, aPrincipal); return NS_OK; } /* static */ void BlobURLProtocolHandler::AddDataEntry(const nsACString& aURI, nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId, BlobImpl* aBlobImpl) { MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aBlobImpl); - AddDataEntryInternal(aURI, aBlobImpl, aPrincipal, aAgentClusterId); + AddDataEntryInternal(aURI, aBlobImpl, aPrincipal); } /* static */ bool BlobURLProtocolHandler::ForEachBlobURL( - std::function&, - const nsACString&, bool aRevoked)>&& aCb) { + std::function&& aCb) { MOZ_ASSERT(NS_IsMainThread()); if (!gDataTable) { @@ -608,8 +598,7 @@ bool BlobURLProtocolHandler::ForEachBlobURL( } MOZ_ASSERT(info->mBlobImpl); - if (!aCb(info->mBlobImpl, info->mPrincipal, info->mAgentClusterId, - iter.Key(), info->mRevoked)) { + if (!aCb(info->mBlobImpl, info->mPrincipal, iter.Key(), info->mRevoked)) { return false; } } @@ -644,34 +633,6 @@ void BlobURLProtocolHandler::RemoveDataEntry(const nsACString& aUri, ReleasingTimerHolder::Create(aUri); } -/*static */ -bool BlobURLProtocolHandler::RemoveDataEntry( - const nsACString& aUri, nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId) { - MOZ_ASSERT(NS_IsMainThread(), "changing gDataTable is main-thread only"); - if (!gDataTable) { - return false; - } - - DataInfo* info = GetDataInfo(aUri); - if (!info) { - return false; - } - - if (!aPrincipal || !aPrincipal->Subsumes(info->mPrincipal)) { - return false; - } - - if (StaticPrefs::privacy_partition_bloburl_per_agent_cluster() && - aAgentClusterId.isSome() && info->mAgentClusterId.isSome() && - !aAgentClusterId.value().Equals(info->mAgentClusterId.value())) { - return false; - } - - RemoveDataEntry(aUri, true); - return true; -} - /* static */ void BlobURLProtocolHandler::RemoveDataEntries() { MOZ_ASSERT(NS_IsMainThread(), "changing gDataTable is main-thread only"); @@ -727,57 +688,21 @@ nsresult BlobURLProtocolHandler::GenerateURIString(nsIPrincipal* aPrincipal, } /* static */ -bool BlobURLProtocolHandler::GetDataEntry( - const nsACString& aUri, BlobImpl** aBlobImpl, - nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, - const OriginAttributes& aOriginAttributes, - const Maybe& aAgentClusterId, bool aAlsoIfRevoked) { +nsIPrincipal* BlobURLProtocolHandler::GetDataEntryPrincipal( + const nsACString& aUri, bool aAlsoIfRevoked) { MOZ_ASSERT(NS_IsMainThread(), "without locking gDataTable is main-thread only"); - MOZ_ASSERT(aTriggeringPrincipal); - if (!gDataTable) { - return false; + return nullptr; } - DataInfo* info = GetDataInfo(aUri, aAlsoIfRevoked); - if (!info) { - return false; + DataInfo* res = GetDataInfo(aUri, aAlsoIfRevoked); + + if (!res) { + return nullptr; } - // We want to be sure that we stop the creation of the channel if the blob - // URL is copy-and-pasted on a different context (ex. private browsing or - // containers). - // - // We also allow the system principal to create the channel regardless of - // the OriginAttributes. This is primarily for the benefit of mechanisms - // like the Download API that explicitly create a channel with the system - // principal and which is never mutated to have a non-zero - // mPrivateBrowsingId or container. - - if (NS_WARN_IF(!aLoadingPrincipal || - !aLoadingPrincipal->IsSystemPrincipal()) && - NS_WARN_IF(!ChromeUtils::IsOriginAttributesEqualIgnoringFPD( - aOriginAttributes, - BasePrincipal::Cast(info->mPrincipal)->OriginAttributesRef()))) { - return false; - } - - if (!aTriggeringPrincipal->Subsumes(info->mPrincipal)) { - return false; - } - - // BlobURLs are openable on the same agent-cluster-id only. - if (StaticPrefs::privacy_partition_bloburl_per_agent_cluster() && - aAgentClusterId.isSome() && info->mAgentClusterId.isSome() && - !aAgentClusterId.value().Equals(info->mAgentClusterId.value())) { - return false; - } - - RefPtr blobImpl = info->mBlobImpl; - blobImpl.forget(aBlobImpl); - - return true; + return res->mPrincipal; } /* static */ diff --git a/dom/file/uri/BlobURLProtocolHandler.h b/dom/file/uri/BlobURLProtocolHandler.h index deca62826475..b9a97687c6ae 100644 --- a/dom/file/uri/BlobURLProtocolHandler.h +++ b/dom/file/uri/BlobURLProtocolHandler.h @@ -21,7 +21,6 @@ class nsIPrincipal; namespace mozilla { class BlobURLsReporter; -class OriginAttributes; namespace dom { @@ -45,37 +44,23 @@ class BlobURLProtocolHandler final : public nsIProtocolHandler, // Methods for managing uri->object mapping // AddDataEntry creates the URI with the given scheme and returns it in aUri - static nsresult AddDataEntry(BlobImpl*, nsIPrincipal*, - const Maybe& aAgentClusterId, - nsACString& aUri); - static nsresult AddDataEntry(MediaSource*, nsIPrincipal*, - const Maybe& aAgentClusterId, - nsACString& aUri); + static nsresult AddDataEntry(BlobImpl*, nsIPrincipal*, nsACString& aUri); + static nsresult AddDataEntry(MediaSource*, nsIPrincipal*, nsACString& aUri); // IPC only - static void AddDataEntry(const nsACString& aURI, nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId, - BlobImpl* aBlobImpl); + static void AddDataEntry(const nsACString& aURI, nsIPrincipal*, BlobImpl*); - // These methods revoke a blobURL. Because some operations could still be in + // This method revokes a blobURL. Because some operations could still be in // progress, the revoking consists in marking the blobURL as revoked and in // removing it after RELEASING_TIMER milliseconds. static void RemoveDataEntry(const nsACString& aUri, bool aBroadcastToOTherProcesses = true); - // Returns true if the entry was allowed to be removed. - static bool RemoveDataEntry(const nsACString& aUri, nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId); static void RemoveDataEntries(); static bool HasDataEntry(const nsACString& aUri); - static bool GetDataEntry(const nsACString& aUri, BlobImpl** aBlobImpl, - nsIPrincipal* aLoadingPrincipal, - nsIPrincipal* aTriggeringPrincipal, - const OriginAttributes& aOriginAttributes, - const Maybe& blobAgentClusterId, - bool aAlsoIfRevoked = false); - + static nsIPrincipal* GetDataEntryPrincipal(const nsACString& aUri, + bool aAlsoIfRevoked = false); static void Traverse(const nsACString& aUri, nsCycleCollectionTraversalCallback& aCallback); @@ -85,8 +70,8 @@ class BlobURLProtocolHandler final : public nsIProtocolHandler, // of an unexpected XPCOM or IPC error). This method returns false if already // shutdown or if the helper method returns false, true otherwise. static bool ForEachBlobURL( - std::function&, - const nsACString&, bool aRevoked)>&& aCb); + std::function&& aCb); // This method returns false if aURI is not a known BlobURL. Otherwise it // returns true. diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 1e591c0e9085..3a25904c0e2d 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -2648,9 +2648,8 @@ mozilla::ipc::IPCResult ContentChild::RecvInitBlobURLs( RefPtr blobImpl = IPCBlobUtils::Deserialize(registration.blob()); MOZ_ASSERT(blobImpl); - BlobURLProtocolHandler::AddDataEntry( - registration.url(), registration.principal(), - registration.agentClusterId(), blobImpl); + BlobURLProtocolHandler::AddDataEntry(registration.url(), + registration.principal(), blobImpl); // If we have received an already-revoked blobURL, we have to keep it alive // for a while (see BlobURLProtocolHandler) in order to support pending // operations such as navigation, download and so on. @@ -3140,12 +3139,11 @@ ContentChild::RecvNotifyPushSubscriptionModifiedObservers( mozilla::ipc::IPCResult ContentChild::RecvBlobURLRegistration( const nsCString& aURI, const IPCBlob& aBlob, - const IPC::Principal& aPrincipal, const Maybe& aAgentClusterId) { + const IPC::Principal& aPrincipal) { RefPtr blobImpl = IPCBlobUtils::Deserialize(aBlob); MOZ_ASSERT(blobImpl); - BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, aAgentClusterId, - blobImpl); + BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, blobImpl); return IPC_OK(); } diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 5a0ddaf43146..e6e3a7f8999c 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -528,7 +528,7 @@ class ContentChild final : public PContentChild, mozilla::ipc::IPCResult RecvBlobURLRegistration( const nsCString& aURI, const IPCBlob& aBlob, - const IPC::Principal& aPrincipal, const Maybe& aAgentClusterId); + const IPC::Principal& aPrincipal); mozilla::ipc::IPCResult RecvBlobURLUnregistration(const nsCString& aURI); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index b8f1e4e0565f..5bde85da2921 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -2866,8 +2866,7 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) { nsTArray registrations; BlobURLProtocolHandler::ForEachBlobURL( [&](BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId, const nsACString& aURI, - bool aRevoked) { + const nsACString& aURI, bool aRevoked) { nsAutoCString origin; nsresult rv = aPrincipal->GetOrigin(origin); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -2891,7 +2890,7 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) { } registrations.AppendElement(BlobURLRegistrationData( - nsCString(aURI), ipcBlob, aPrincipal, aAgentClusterId, aRevoked)); + nsCString(aURI), ipcBlob, aPrincipal, aRevoked)); rv = TransmitPermissionsForPrincipal(aPrincipal); Unused << NS_WARN_IF(NS_FAILED(rv)); @@ -5492,9 +5491,10 @@ ContentParent::RecvNotifyPushSubscriptionModifiedObservers( } /* static */ -void ContentParent::BroadcastBlobURLRegistration( - const nsACString& aURI, BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId, ContentParent* aIgnoreThisCP) { +void ContentParent::BroadcastBlobURLRegistration(const nsACString& aURI, + BlobImpl* aBlobImpl, + nsIPrincipal* aPrincipal, + ContentParent* aIgnoreThisCP) { nsAutoCString origin; nsresult rv = aPrincipal->GetOrigin(origin); NS_ENSURE_SUCCESS_VOID(rv); @@ -5524,8 +5524,7 @@ void ContentParent::BroadcastBlobURLRegistration( break; } - Unused << cp->SendBlobURLRegistration(uri, ipcBlob, principal, - aAgentClusterId); + Unused << cp->SendBlobURLRegistration(uri, ipcBlob, principal); } } } @@ -5554,18 +5553,14 @@ void ContentParent::BroadcastBlobURLUnregistration( } mozilla::ipc::IPCResult ContentParent::RecvStoreAndBroadcastBlobURLRegistration( - const nsCString& aURI, const IPCBlob& aBlob, const Principal& aPrincipal, - const Maybe& aAgentClusterId) { + const nsCString& aURI, const IPCBlob& aBlob, const Principal& aPrincipal) { RefPtr blobImpl = IPCBlobUtils::Deserialize(aBlob); if (NS_WARN_IF(!blobImpl)) { return IPC_FAIL_NO_REASON(this); } - BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, aAgentClusterId, - blobImpl); - BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, aAgentClusterId, - this); - + BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, blobImpl); + BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, this); // We want to store this blobURL, so we can unregister it if the child // crashes. mBlobURLs.AppendElement(aURI); @@ -5806,8 +5801,7 @@ void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) { nsTArray registrations; BlobURLProtocolHandler::ForEachBlobURL( [&](BlobImpl* aBlobImpl, nsIPrincipal* aBlobPrincipal, - const Maybe& aAgentClusterId, const nsACString& aURI, - bool aRevoked) { + const nsACString& aURI, bool aRevoked) { if (!aPrincipal->Subsumes(aBlobPrincipal)) { return true; } @@ -5819,7 +5813,7 @@ void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) { } registrations.AppendElement(BlobURLRegistrationData( - nsCString(aURI), ipcBlob, aPrincipal, aAgentClusterId, aRevoked)); + nsCString(aURI), ipcBlob, aPrincipal, aRevoked)); rv = TransmitPermissionsForPrincipal(aPrincipal); Unused << NS_WARN_IF(NS_FAILED(rv)); @@ -6832,24 +6826,60 @@ PFileDescriptorSetParent* ContentParent::SendPFileDescriptorSetConstructor( } mozilla::ipc::IPCResult ContentParent::RecvBlobURLDataRequest( - const nsCString& aBlobURL, nsIPrincipal* aTriggeringPrincipal, - nsIPrincipal* aLoadingPrincipal, const OriginAttributes& aOriginAttributes, - const Maybe& aAgentClusterId, + const nsCString& aBlobURL, nsIPrincipal* pTriggeringPrincipal, + nsIPrincipal* pLoadingPrincipal, const OriginAttributes& aOriginAttributes, BlobURLDataRequestResolver&& aResolver) { RefPtr blobImpl; + nsresult rv = NS_GetBlobForBlobURISpec(aBlobURL, getter_AddRefs(blobImpl), + true /* AlsoIfRevoked */); + + if (NS_WARN_IF(NS_FAILED(rv))) { + aResolver(rv); + return IPC_OK(); + } + + if (NS_WARN_IF(!blobImpl)) { + aResolver(NS_ERROR_DOM_BAD_URI); + return IPC_OK(); + } // Since revoked blobs are also retrieved, it is possible that the blob no // longer exists (due to the 5 second timeout) when execution reaches here - if (!BlobURLProtocolHandler::GetDataEntry( - aBlobURL, getter_AddRefs(blobImpl), aLoadingPrincipal, - aTriggeringPrincipal, aOriginAttributes, aAgentClusterId, - true /* AlsoIfRevoked */)) { + nsIPrincipal* const dataEntryPrincipal = + BlobURLProtocolHandler::GetDataEntryPrincipal(aBlobURL, + true /* AlsoIfRevoked */); + + if (!dataEntryPrincipal) { + aResolver(NS_ERROR_DOM_BAD_URI); + return IPC_OK(); + } + + // We want to be sure that we stop the creation of the channel if the blob + // URL is copy-and-pasted on a different context (ex. private browsing or + // containers). + // + // We also allow the system principal to create the channel regardless of + // the OriginAttributes. This is primarily for the benefit of mechanisms + // like the Download API that explicitly create a channel with the system + // principal and which is never mutated to have a non-zero + // mPrivateBrowsingId or container. + + if (NS_WARN_IF(!pLoadingPrincipal || + !pLoadingPrincipal->IsSystemPrincipal()) && + NS_WARN_IF(!ChromeUtils::IsOriginAttributesEqualIgnoringFPD( + aOriginAttributes, + BasePrincipal::Cast(dataEntryPrincipal)->OriginAttributesRef()))) { + aResolver(NS_ERROR_DOM_BAD_URI); + return IPC_OK(); + } + + if (!pTriggeringPrincipal->Subsumes(dataEntryPrincipal)) { aResolver(NS_ERROR_DOM_BAD_URI); return IPC_OK(); } IPCBlob ipcBlob; - nsresult rv = IPCBlobUtils::Serialize(blobImpl, this, ipcBlob); + rv = IPCBlobUtils::Serialize(blobImpl, this, ipcBlob); if (NS_WARN_IF(NS_FAILED(rv))) { aResolver(rv); diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 59f88cf0c5c7..8ca49a475fde 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -548,7 +548,6 @@ class ContentParent final static void BroadcastBlobURLRegistration( const nsACString& aURI, BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal, - const Maybe& aAgentClusterId, ContentParent* aIgnoreThisCP = nullptr); static void BroadcastBlobURLUnregistration( @@ -556,8 +555,7 @@ class ContentParent final ContentParent* aIgnoreThisCP = nullptr); mozilla::ipc::IPCResult RecvStoreAndBroadcastBlobURLRegistration( - const nsCString& aURI, const IPCBlob& aBlob, const Principal& aPrincipal, - const Maybe& aAgentCluster); + const nsCString& aURI, const IPCBlob& aBlob, const Principal& aPrincipal); mozilla::ipc::IPCResult RecvUnstoreAndBroadcastBlobURLUnregistration( const nsCString& aURI, const Principal& aPrincipal); @@ -703,7 +701,6 @@ class ContentParent final const nsCString& aBlobURL, nsIPrincipal* pTriggeringPrincipal, nsIPrincipal* pLoadingPrincipal, const OriginAttributes& aOriginAttributes, - const Maybe& aAgentClusterId, BlobURLDataRequestResolver&& aResolver); protected: diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 0ee444f4dff1..72708034eb6a 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -235,7 +235,6 @@ struct BlobURLRegistrationData nsCString url; IPCBlob blob; nsIPrincipal principal; - nsID? agentClusterId; bool revoked; }; @@ -750,8 +749,7 @@ child: async GetFilesResponse(nsID aID, GetFilesResponseResult aResult); async BlobURLRegistration(nsCString aURI, IPCBlob aBlob, - Principal aPrincipal, - nsID? aAgentClusterId); + Principal aPrincipal); async BlobURLUnregistration(nsCString aURI); @@ -1491,8 +1489,7 @@ parent: async DeleteGetFilesRequest(nsID aID); async StoreAndBroadcastBlobURLRegistration(nsCString url, IPCBlob blob, - Principal principal, - nsID? aAgentClusterId); + Principal principal); async UnstoreAndBroadcastBlobURLUnregistration(nsCString url, Principal principal); @@ -1660,12 +1657,7 @@ parent: async HistoryGo(MaybeDiscardedBrowsingContext aContext, int32_t aOffset) returns(int32_t requestedIndex); - async BlobURLDataRequest(nsCString aBlobURL, - nsIPrincipal aTriggeringPrincipal, - nsIPrincipal aLoadingPrincipal, - OriginAttributes aOriginAttributes, - nsID? aAgentClusterId) - returns (BlobURLDataRequestResult aResult); + async BlobURLDataRequest(nsCString aBlobURL, nsIPrincipal aTriggeringPrincipal, nsIPrincipal aLoadingPrincipal, OriginAttributes aOriginAttributes) returns (BlobURLDataRequestResult aResult); both: async ScriptError(nsString message, nsString sourceName, nsString sourceLine, diff --git a/dom/url/URLMainThread.cpp b/dom/url/URLMainThread.cpp index e67b3b8e48c0..5dcdc8697cb6 100644 --- a/dom/url/URLMainThread.cpp +++ b/dom/url/URLMainThread.cpp @@ -31,8 +31,7 @@ void URLMainThread::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, nsContentUtils::ObjectPrincipal(aGlobal.Get()); nsAutoCString url; - aRv = BlobURLProtocolHandler::AddDataEntry(aBlob.Impl(), principal, - global->GetAgentClusterId(), url); + aRv = BlobURLProtocolHandler::AddDataEntry(aBlob.Impl(), principal, url); if (NS_WARN_IF(aRv.Failed())) { return; } @@ -47,18 +46,11 @@ void URLMainThread::CreateObjectURL(const GlobalObject& aGlobal, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); - if (NS_WARN_IF(!global)) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - nsCOMPtr principal = nsContentUtils::ObjectPrincipal(aGlobal.Get()); nsAutoCString url; - aRv = BlobURLProtocolHandler::AddDataEntry(&aSource, principal, - global->GetAgentClusterId(), url); + aRv = BlobURLProtocolHandler::AddDataEntry(&aSource, principal, url); if (NS_WARN_IF(aRv.Failed())) { return; } @@ -82,12 +74,16 @@ void URLMainThread::RevokeObjectURL(const GlobalObject& aGlobal, return; } + nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal.Get()); + NS_LossyConvertUTF16toASCII asciiurl(aURL); - if (BlobURLProtocolHandler::RemoveDataEntry( - asciiurl, nsContentUtils::ObjectPrincipal(aGlobal.Get()), - global->GetAgentClusterId())) { + nsIPrincipal* urlPrincipal = + BlobURLProtocolHandler::GetDataEntryPrincipal(asciiurl); + + if (urlPrincipal && principal->Subsumes(urlPrincipal)) { global->UnregisterHostObjectURI(asciiurl); + BlobURLProtocolHandler::RemoveDataEntry(asciiurl); } } diff --git a/dom/url/URLWorker.cpp b/dom/url/URLWorker.cpp index bd06ddc6d06f..c06649a92337 100644 --- a/dom/url/URLWorker.cpp +++ b/dom/url/URLWorker.cpp @@ -38,8 +38,8 @@ class CreateURLRunnable : public WorkerMainThreadRunnable { nsCOMPtr principal = mWorkerPrivate->GetPrincipal(); nsAutoCString url; - nsresult rv = BlobURLProtocolHandler::AddDataEntry( - mBlobImpl, principal, Some(mWorkerPrivate->AgentClusterId()), url); + nsresult rv = + BlobURLProtocolHandler::AddDataEntry(mBlobImpl, principal, url); if (NS_FAILED(rv)) { NS_WARNING("Failed to add data entry for the blob!"); @@ -67,9 +67,18 @@ class RevokeURLRunnable : public WorkerMainThreadRunnable { NS_ConvertUTF16toUTF8 url(mURL); - BlobURLProtocolHandler::RemoveDataEntry( - url, mWorkerPrivate->GetPrincipal(), - Some(mWorkerPrivate->AgentClusterId())); + nsIPrincipal* urlPrincipal = + BlobURLProtocolHandler::GetDataEntryPrincipal(url); + + nsCOMPtr principal = mWorkerPrivate->GetPrincipal(); + + bool subsumes; + if (urlPrincipal && + NS_SUCCEEDED(principal->Subsumes(urlPrincipal, &subsumes)) && + subsumes) { + BlobURLProtocolHandler::RemoveDataEntry(url); + } + return true; } }; diff --git a/dom/url/tests/test_bloburl_location.html b/dom/url/tests/test_bloburl_location.html index f8442cffc524..446b50836c37 100644 --- a/dom/url/tests/test_bloburl_location.html +++ b/dom/url/tests/test_bloburl_location.html @@ -19,14 +19,10 @@ onmessage = function(e) { } }; -SpecialPowers.pushPrefEnv({ - "set": [["privacy.partition.bloburl_per_agent_cluster", false]] -}).then(() => { - var ifr = document.createElement("iframe"); - document.body.appendChild(ifr); +var ifr = document.createElement("iframe"); +document.body.appendChild(ifr); - ifr.src = "data:text/html,