diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp index 466c28d578ec..3fbb4fe35f2c 100644 --- a/docshell/base/BrowsingContext.cpp +++ b/docshell/base/BrowsingContext.cpp @@ -1968,8 +1968,7 @@ nsresult BrowsingContext::LoadURI(nsDocShellLoadState* aLoadState, aLoadState->SetChannelInitialized(true); } - cp->TransmitBlobDataIfBlobURL(aLoadState->URI(), - aLoadState->TriggeringPrincipal()); + cp->TransmitBlobDataIfBlobURL(aLoadState->URI()); // Setup a confirmation callback once the content process receives this // load. Normally we'd expect a PDocumentChannel actor to have been diff --git a/dom/file/uri/BlobURLProtocolHandler.cpp b/dom/file/uri/BlobURLProtocolHandler.cpp index 810d8e3d5cec..cc94be5e112d 100644 --- a/dom/file/uri/BlobURLProtocolHandler.cpp +++ b/dom/file/uri/BlobURLProtocolHandler.cpp @@ -929,6 +929,12 @@ bool BlobURLProtocolHandler::GetBlobURLPrincipal(nsIURI* aURI, return true; } +bool BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal( + nsIPrincipal* aPrincipal) { + return aPrincipal->IsSystemPrincipal() || + aPrincipal->GetIsAddonOrExpandedAddonPrincipal(); +} + } // namespace dom } // namespace mozilla diff --git a/dom/file/uri/BlobURLProtocolHandler.h b/dom/file/uri/BlobURLProtocolHandler.h index 46c31b9154d5..5eb0192a4778 100644 --- a/dom/file/uri/BlobURLProtocolHandler.h +++ b/dom/file/uri/BlobURLProtocolHandler.h @@ -105,6 +105,12 @@ class BlobURLProtocolHandler final : public nsIProtocolHandler, // fired. See RemoveDataEntry(). static bool GetBlobURLPrincipal(nsIURI* aURI, nsIPrincipal** aPrincipal); + // Check if metadata about Blob URLs created with this principal should be + // broadcast into every content process. This is currently the case for + // extension blob URLs and system principal blob URLs, as they can be loaded + // by system code and content scripts respectively. + static bool IsBlobURLBroadcastPrincipal(nsIPrincipal* aPrincipal); + private: ~BlobURLProtocolHandler(); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 2a7ad7c9e331..a9d12a053838 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -3111,24 +3111,18 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) { [&](BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal, const Maybe& aAgentClusterId, const nsACString& aURI, bool aRevoked) { - nsAutoCString origin; - nsresult rv = aPrincipal->GetOrigin(origin); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - // We send all moz-extension Blob URL's to all content processes // because content scripts mean that a moz-extension can live in any // process. Same thing for system principal Blob URLs. Content Blob // URL's are sent for content principals on-demand by // AboutToLoadHttpFtpDocumentForChild and RemoteWorkerManager. - if (!StringBeginsWith(origin, "moz-extension://"_ns) && - !aPrincipal->IsSystemPrincipal()) { + if (!BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal( + aPrincipal)) { return true; } IPCBlob ipcBlob; - rv = IPCBlobUtils::Serialize(aBlobImpl, this, ipcBlob); + nsresult rv = IPCBlobUtils::Serialize(aBlobImpl, this, ipcBlob); if (NS_WARN_IF(NS_FAILED(rv))) { return false; } @@ -5723,14 +5717,10 @@ ContentParent::RecvNotifyPushSubscriptionModifiedObservers( void ContentParent::BroadcastBlobURLRegistration( const nsACString& aURI, BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal, const Maybe& aAgentClusterId, ContentParent* aIgnoreThisCP) { - nsAutoCString origin; - nsresult rv = aPrincipal->GetOrigin(origin); - NS_ENSURE_SUCCESS_VOID(rv); - uint64_t originHash = ComputeLoadedOriginHash(aPrincipal); - bool toBeSent = StringBeginsWith(origin, "moz-extension://"_ns) || - aPrincipal->IsSystemPrincipal(); + bool toBeSent = + BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal); nsCString uri(aURI); IPC::Principal principal(aPrincipal); @@ -5762,14 +5752,10 @@ void ContentParent::BroadcastBlobURLRegistration( void ContentParent::BroadcastBlobURLUnregistration( const nsACString& aURI, nsIPrincipal* aPrincipal, ContentParent* aIgnoreThisCP) { - nsAutoCString origin; - nsresult rv = aPrincipal->GetOrigin(origin); - NS_ENSURE_SUCCESS_VOID(rv); - uint64_t originHash = ComputeLoadedOriginHash(aPrincipal); - bool toBeSent = StringBeginsWith(origin, "moz-extension://"_ns) || - aPrincipal->IsSystemPrincipal(); + bool toBeSent = + BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal); nsCString uri(aURI); @@ -6025,6 +6011,21 @@ nsresult ContentParent::TransmitPermissionsForPrincipal( } void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) { + // If we're already broadcasting BlobURLs with this principal, we don't need + // to send them here. + if (BlobURLProtocolHandler::IsBlobURLBroadcastPrincipal(aPrincipal)) { + return; + } + + // We shouldn't have any Blob URLs with expanded principals, so transmit URLs + // for each principal in the AllowList instead. + if (nsCOMPtr ep = do_QueryInterface(aPrincipal)) { + for (const auto& prin : ep->AllowList()) { + TransmitBlobURLsForPrincipal(prin); + } + return; + } + uint64_t originHash = ComputeLoadedOriginHash(aPrincipal); if (!mLoadedOriginHashes.Contains(originHash)) { @@ -6035,7 +6036,10 @@ void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) { [&](BlobImpl* aBlobImpl, nsIPrincipal* aBlobPrincipal, const Maybe& aAgentClusterId, const nsACString& aURI, bool aRevoked) { - if (!aPrincipal->Subsumes(aBlobPrincipal)) { + // This check uses `ComputeLoadedOriginHash` to compare, rather than + // doing the more accurate `Equals` check, as it needs to match the + // behaviour of the logic to broadcast new registrations. + if (originHash != ComputeLoadedOriginHash(aBlobPrincipal)) { return true; } @@ -6049,7 +6053,7 @@ void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) { BlobURLRegistrationData(nsCString(aURI), ipcBlob, aBlobPrincipal, aAgentClusterId, aRevoked)); - rv = TransmitPermissionsForPrincipal(aPrincipal); + rv = TransmitPermissionsForPrincipal(aBlobPrincipal); Unused << NS_WARN_IF(NS_FAILED(rv)); return true; }); @@ -6060,16 +6064,14 @@ void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) { } } -void ContentParent::TransmitBlobDataIfBlobURL(nsIURI* aURI, - nsIPrincipal* aPrincipal) { +void ContentParent::TransmitBlobDataIfBlobURL(nsIURI* aURI) { MOZ_ASSERT(aURI); - MOZ_ASSERT(aPrincipal); - if (!IsBlobURI(aURI)) { - return; + nsCOMPtr principal; + if (BlobURLProtocolHandler::GetBlobURLPrincipal(aURI, + getter_AddRefs(principal))) { + TransmitBlobURLsForPrincipal(principal); } - - TransmitBlobURLsForPrincipal(aPrincipal); } void ContentParent::EnsurePermissionsByKey(const nsCString& aKey, diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index c59adbb02801..a7cee0dae75b 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -631,8 +631,8 @@ class ContentParent final // This function is called in BrowsingContext immediately before IPC call to // load a URI. If aURI is a BlobURL, this method transmits all BlobURLs for - // aPrincipal that were previously not transmitted. This allows for opening a - // locally created BlobURL in a new tab. + // aURI's principal that were previously not transmitted. This allows for + // opening a locally created BlobURL in a new tab. // // The reason all previously untransmitted Blobs are transmitted is that the // current BlobURL could contain html code, referring to another untransmitted @@ -640,7 +640,7 @@ class ContentParent final // // Should eventually be made obsolete by broader design changes that only // store BlobURLs in the parent process. - void TransmitBlobDataIfBlobURL(nsIURI* aURI, nsIPrincipal* aPrincipal); + void TransmitBlobDataIfBlobURL(nsIURI* aURI); void OnCompositorDeviceReset() override; diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp index ab290b87d9c7..5601c18fe29c 100644 --- a/netwerk/ipc/DocumentLoadListener.cpp +++ b/netwerk/ipc/DocumentLoadListener.cpp @@ -1918,14 +1918,7 @@ DocumentLoadListener::RedirectToRealChannel( CreateAndReject(ipc::ResponseRejectReason::SendError, __func__); } - auto triggeringPrincipalOrErr = - PrincipalInfoToPrincipal(loadInfo.ref().triggeringPrincipalInfo()); - - if (triggeringPrincipalOrErr.isOk()) { - nsCOMPtr triggeringPrincipal = - triggeringPrincipalOrErr.unwrap(); - cp->TransmitBlobDataIfBlobURL(args.uri(), triggeringPrincipal); - } + cp->TransmitBlobDataIfBlobURL(args.uri()); return cp->SendCrossProcessRedirect(args, std::move(aStreamFilterEndpoints));