CVE-2026-79289
Overview
Background
- `DedicatedWorkerHostFactoryImpl`
- A browser-process (UI-thread) Mojo interface implementation that manufactures
DedicatedWorkerHosts on behalf of a creator frame or worker, capturing that creator’sStorageKey,IsolationInfo, andClientSecurityStateat bind time. - `MakeSelfOwnedReceiver` / `SelfOwnedReceiver`
- A Mojo lifetime model in which the implementation object lives until its own message pipe is closed, independent of any document or frame lifetime.
- `DocumentService<T>`
- A Mojo receiver base class that binds an implementation to a specific
RenderFrameHost’s current document and automatically destroys it when that document is deleted or the frame commits a cross-document navigation. - `WeakDocumentPtr` / `ancestor_document_`
- A weak reference to the document that created the worker; the factory holds it to route later worker creation to the correct frame.
Root Cause Analysis
DedicatedWorkerHostFactoryImpl snapshots security-critical state (StorageKey, IsolationInfo, ClientSecurityState, policies, network restrictions) belonging to its creator document at construction, so its validity is tied to that document. Before the patch, both entry points — RenderFrameHostImpl::CreateDedicatedWorkerHostFactory() and DedicatedWorkerHost::CreateNestedDedicatedWorker() — bound the factory with mojo::MakeSelfOwnedReceiver, meaning the factory’s lifetime was governed only by the renderer-controlled message pipe and could outlive the creator document (for example across a cross-document navigation). A factory that outlived its document would keep vending workers using the stale captured security context, an improper resource-lifetime condition (the bug class is a logic/lifetime error).
The fix converts DedicatedWorkerHostFactoryImpl to a DocumentService<blink::mojom::DedicatedWorkerHostFactory>, routes both call sites through a static Create() that scopes the instance to the ancestor RenderFrameHost’s current document, and — in the nested case — first resolves ancestor_document_.AsRenderFrameHostIfValid() and aborts (returns) if the ancestor frame is already gone. DocumentService then tears the receiver down on document destruction or cross-document navigation, so the factory can no longer serve requests with a stale context (confirmed by the added FactoryResetOnCrossDocumentNavigation test, which asserts the factory disconnects after navigating A→B).
SelfOwnedReceiver lifetime decoupled from that document, letting a renderer keep it alive past the document’s teardown; converting it to DocumentService (plus a null-ancestor abort in the nested path) binds its lifetime to the document whose context it holds.Attack Path
- Obtain a worker factory
A renderer requests a
DedicatedWorkerHostFactoryfrom its frame (CreateDedicatedWorkerHostFactory) or nested worker path, causing the browser to bind aDedicatedWorkerHostFactoryImplthat captures the current document’sStorageKey/IsolationInfo/ClientSecurityState. - Keep the pipe open across a navigation Because the receiver was self-owned, the renderer holds the factory pipe open while the frame commits a cross-document navigation, so the factory survives destruction of the document whose security context it captured.
- Vend a worker with stale context
The renderer then drives the still-connected factory to create a
DedicatedWorkerHost, which is initialized with the previous document’s capturedStorageKey/isolation/security state rather than the new document’s. (inferred: use of the mismatched context to access storage or network resources scoped to the old document.) - Fixed behavior
After the patch, the
DocumentServicebinding disconnects the factory on the cross-document commit (andCreateNestedDedicatedWorkerreturns early when the ancestor frame is gone), so step 3 cannot occur.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcontent/browser/worker_host/dedicated_worker_host.cc |
modified | |
RenderFrameHostcontent/browser/worker_host/dedicated_worker_host_factory_impl.h |
modified | |
CONTENT_EXPORTcontent/browser/worker_host/dedicated_worker_host_factory_impl.h |
modified | |
TEST_Fcontent/browser/worker_host/dedicated_worker_service_impl_unittest.cc |
modified |
Files Changed
content/browser/worker_host/dedicated_worker_host_factory_impl.hcontent/browser/worker_host/dedicated_worker_service_impl_unittest.cccontent/browser/renderer_host/render_frame_host_impl.cccontent/browser/worker_host/dedicated_worker_host.cccontent/browser/worker_host/dedicated_worker_host_factory_impl.cc
Audit Directions
- Captured-context objects with self-owned lifetimesSearch for
mojo::MakeSelfOwnedReceiveron implementations that snapshot a document’s or frame’s security state (StorageKey,IsolationInfo,ClientSecurityState, policies); these should generally beDocumentService/DocumentUserDataso they die with their context. - Ancestor/creator weak pointers used without validity checksReview paths that dereference or bind against a
WeakDocumentPtr/creator frame (e.g. nested worker or nested factory creation) and confirm they checkAsRenderFrameHostIfValid()and abort when the ancestor is gone. - Lifetime mismatch across navigationFor any browser-side Mojo interface exposed to renderers, verify a cross-document navigation of the owning frame tears down or rebinds the receiver, rather than leaving it serving with pre-navigation state.
Patch
From cef96269cafaa6f303d44ef4ef6c7f08cf8228d9 Mon Sep 17 00:00:00 2001 From: Yoshisto Yanagisawa <[email protected]> Date: Thu, 09 Jul 2026 00:37:53 -0700 Subject: [PATCH] [DedicatedWorker] Scope DedicatedWorkerHostFactoryImpl to the creator document DedicatedWorkerHostFactoryImpl captures its creator's StorageKey, IsolationInfo and ClientSecurityState at bind time, so it should not outlive the document that requested it. Convert it to a DocumentService<blink::mojom::DedicatedWorkerHostFactory> so the receiver is torn down when the ancestor RenderFrameHost is deleted or commits a cross-document navigation. Both the frame-creator path (RenderFrameHostImpl::CreateDedicatedWorkerHostFactory) and the worker-creator path (DedicatedWorkerHost::CreateNestedDedicatedWorker) now go through a static Create() that scopes the instance to the ancestor RFH's current document. Existing unit tests are migrated to the new API and a regression test is added. Bug: 497876969 Change-Id: I2322c94b8e788e6960cd0b499b5e2eb6bd8571af Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8035382 Commit-Queue: Yoshisato Yanagisawa <[email protected]> Reviewed-by: Rakina Zata Amni <[email protected]> Cr-Commit-Position: refs/heads/main@{#1659365} --- diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 4c38ac1..f19b1a8f 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc @@ -14859,14 +14859,13 @@ // When a dedicated worker is created from the frame script, the frame is both // the creator and the ancestor. - mojo::MakeSelfOwnedReceiver( - std::make_unique<DedicatedWorkerHostFactoryImpl>( - worker_process_id, - /*creator=*/GetGlobalId(), GetWeakDocumentPtr(), GetStorageKey(), - isolation_info_, BuildClientSecurityState(), - policy_container_host()->policies(), - /*creator_coep_reporter=*/coep_reporter, GetNetworkRestrictionsID()), - std::move(receiver)); + DedicatedWorkerHostFactoryImpl::Create( + *this, std::move(receiver), worker_process_id, + /*creator=*/GetGlobalId(), + /*ancestor_document=*/GetWeakDocumentPtr(), GetStorageKey(), + isolation_info_, BuildClientSecurityState(), + policy_container_host()->policies(), + /*creator_coep_reporter=*/coep_reporter, GetNetworkRestrictionsID()); } #if BUILDFLAG(IS_ANDROID) || (BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_IOS_TVOS)) diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc index 656b953..c7fc66c 100644 --- a/content/browser/worker_host/dedicated_worker_host.cc +++ b/content/browser/worker_host/dedicated_worker_host.cc @@ -857,16 +857,23 @@ void DedicatedWorkerHost::CreateNestedDedicatedWorker( mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + RenderFrameHost* ancestor_render_frame_host = + ancestor_document_.AsRenderFrameHostIfValid(); + if (!ancestor_render_frame_host) { + // The ancestor frame may have already been closed. In that case, the worker + // will soon be terminated too, so abort the connection. + return; + } + base::WeakPtr<CrossOriginEmbedderPolicyReporter> creator_coep_reporter = GetWorkerCoepReporter(); - mojo::MakeSelfOwnedReceiver( - std::make_unique<DedicatedWorkerHostFactoryImpl>( - worker_process_host_->GetID(), /*creator=*/token_, ancestor_document_, - GetWorkerStorageKey(), isolation_info_, - worker_client_security_state_->Clone(), creator_policies_, - creator_coep_reporter, network_restrictions_id_), - std::move(receiver)); + DedicatedWorkerHostFactoryImpl::Create( + *ancestor_render_frame_host, std::move(receiver), + worker_process_host_->GetID(), /*creator=*/token_, ancestor_document_, + GetWorkerStorageKey(), isolation_info_, + worker_client_security_state_->Clone(), creator_policies_, + creator_coep_reporter, network_restrictions_id_); } void DedicatedWorkerHost::CreateIdleManager( diff --git a/content/browser/worker_host/dedicated_worker_host_factory_impl.cc b/content/browser/worker_host/dedicated_worker_host_factory_impl.cc index e6ccdba4..b32393d1 100644 --- a/content/browser/worker_host/dedicated_worker_host_factory_impl.cc +++ b/content/browser/worker_host/dedicated_worker_host_factory_impl.cc @@ -47,7 +47,32 @@ } // namespace +// static +void DedicatedWorkerHostFactoryImpl::Create( + RenderFrameHost& ancestor_render_frame_host, + mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver, + ChildProcessId worker_process_id, + DedicatedWorkerCreator creator, + WeakDocumentPtr ancestor_document, + const blink::StorageKey& creator_storage_key, + const net::IsolationInfo& isolation_info, + network::mojom::ClientSecurityStatePtr creator_client_security_state, + const PolicyContainerPolicies& creator_policies, + base::WeakPtr<CrossOriginEmbedderPolicyReporter> creator_coep_reporter, + const base::UnguessableToken& creator_network_restrictions_id) { + // The factory deletes itself when the receiver is disconnected or when the + // ancestor RenderFrameHost commits a cross-document navigation. + new DedicatedWorkerHostFactoryImpl( + ancestor_render_frame_host, std::move(receiver), worker_process_id, + creator, std::move(ancestor_document), creator_storage_key, + isolation_info, std::move(creator_client_security_state), + creator_policies, std::move(creator_coep_reporter), + creator_network_restrictions_id); +} + DedicatedWorkerHostFactoryImpl::DedicatedWorkerHostFactoryImpl( + RenderFrameHost& ancestor_render_frame_host, + mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver, ChildProcessId worker_process_id, DedicatedWorkerCreator creator, WeakDocumentPtr ancestor_document, @@ -57,7 +82,8 @@ const PolicyContainerPolicies& creator_policies, base::WeakPtr<CrossOriginEmbedderPolicyReporter> creator_coep_reporter, const base::UnguessableToken& creator_network_restrictions_id) - : worker_process_id_(worker_process_id), + : DocumentService(ancestor_render_frame_host, std::move(receiver)), + worker_process_id_(worker_process_id), creator_(creator), ancestor_document_(std::move(ancestor_document)), creator_storage_key_(creator_storage_key), diff --git a/content/browser/worker_host/dedicated_worker_host_factory_impl.h b/content/browser/worker_host/dedicated_worker_host_factory_impl.h index 15e5e923..8b94d54 100644 --- a/content/browser/worker_host/dedicated_worker_host_factory_impl.h +++ b/content/browser/worker_host/dedicated_worker_host_factory_impl.h @@ -9,9 +9,11 @@ #include "content/browser/renderer_host/policy_container_host.h" #include "content/common/content_export.h" #include "content/public/browser/dedicated_worker_creator.h" +#include "content/public/browser/document_service.h" #include "content/public/browser/global_routing_id.h" #include "content/public/browser/weak_document_ptr.h" #include "content/public/common/child_process_id.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "net/base/isolation_info.h" #include "net/storage_access_api/status.h" @@ -23,23 +25,31 @@ namespace content { -// A factory for creating DedicatedWorkerHosts. Its lifetime is managed by the -// renderer over mojo via SelfOwnedReceiver. It lives on the UI thread. +class RenderFrameHost; + +// A factory for creating DedicatedWorkerHosts. Its lifetime is scoped to the +// current document of the ancestor RenderFrameHost via DocumentService. It +// lives on the UI thread. // // A factory instance creates at most one `DedicatedWorkerHost` instance. -class CONTENT_EXPORT DedicatedWorkerHostFactoryImpl - : public blink::mojom::DedicatedWorkerHostFactory { +class CONTENT_EXPORT DedicatedWorkerHostFactoryImpl final + : public DocumentService<blink::mojom::DedicatedWorkerHostFactory> { public: using CreateWorkerHostCallback = base::OnceCallback<void( const network::CrossOriginEmbedderPolicy&, mojo::PendingRemote<blink::mojom::BackForwardCacheControllerHost>)>; + // Creates and binds an instance scoped to `ancestor_render_frame_host`'s + // current document. + // // `creator_client_security_state` specifies the client security state of // the creator frame or worker. Must not be nullptr. // `creator_policies` specifies the security policies of the creator. // `creator_network_restrictions_id` specifies the network restrictions of // the creator as per its connection allowlists. - DedicatedWorkerHostFactoryImpl( + static void Create( + RenderFrameHost& ancestor_render_frame_host, + mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver, ChildProcessId worker_process_id, DedicatedWorkerCreator creator, WeakDocumentPtr ancestor_document, @@ -55,6 +65,21 @@ DedicatedWorkerHostFactoryImpl& operator=( const DedicatedWorkerHostFactoryImpl&) = delete; + private: + DedicatedWorkerHostFactoryImpl( + RenderFrameHost& ancestor_render_frame_host, + mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver, + ChildProcessId worker_process_id, + DedicatedWorkerCreator creator, + WeakDocumentPtr ancestor_document, + const blink::StorageKey& creator_storage_key, + const net::IsolationInfo& isolation_info, + network::mojom::ClientSecurityStatePtr creator_client_security_state, + const PolicyContainerPolicies& creator_policies, + base::WeakPtr<CrossOriginEmbedderPolicyReporter> creator_coep_reporter, + const base::UnguessableToken& creator_network_restrictions_id); + + // `this` can only be destroyed by DocumentService. ~DedicatedWorkerHostFactoryImpl() override; // blink::mojom::DedicatedWorkerHostFactory: @@ -69,7 +94,6 @@ client, net::StorageAccessApiStatus storage_access_api_status) override; - private: // The ID of the RenderProcessHost where the worker will live. const ChildProcessId worker_process_id_; diff --git a/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc b/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc index 4b99649..7249859 100644 --- a/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc +++ b/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc @@ -18,6 +18,7 @@ #include "content/browser/worker_host/dedicated_worker_host.h" #include "content/browser/worker_host/dedicated_worker_host_factory_impl.h" #include "content/common/content_navigation_policy.h" +#include "content/public/browser/back_forward_cache.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/content_features.h" #include "content/public/test/navigation_simulator.h" @@ -27,7 +28,6 @@ #include "content/test/test_render_view_host.h" #include "content/test/test_web_contents.h" #include "mojo/public/cpp/bindings/remote.h" -#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "mojo/public/cpp/test_support/test_utils.h" #include "net/base/isolation_info.h" #include "net/storage_access_api/status.h" @@ -62,17 +62,15 @@ GURL(), std::nullopt, std::nullopt, base::UnguessableToken::Create(), net::NetworkAnonymizationKey()); - mojo::MakeSelfOwnedReceiver( - std::make_unique<DedicatedWorkerHostFactoryImpl>( - worker_process_id, /*creator=*/render_frame_host_id, - RenderFrameHostImpl::FromID(render_frame_host_id) - ->GetWeakDocumentPtr(), - blink::StorageKey::CreateFirstParty(origin), - net::IsolationInfo::CreateTransient(/*nonce=*/std::nullopt), - network::mojom::ClientSecurityState::New(), - PolicyContainerPolicies(), coep_reporter->GetWeakPtr(), - network::GetTestNetworkRestrictionsId()), - factory_.BindNewPipeAndPassReceiver()); + DedicatedWorkerHostFactoryImpl::Create( + *RenderFrameHostImpl::FromID(render_frame_host_id), + factory_.BindNewPipeAndPassReceiver(), worker_process_id, + /*creator=*/render_frame_host_id, + RenderFrameHostImpl::FromID(render_frame_host_id)->GetWeakDocumentPtr(), + blink::StorageKey::CreateFirstParty(origin), + net::IsolationInfo::CreateTransient(/*nonce=*/std::nullopt), + network::mojom::ClientSecurityState::New(), PolicyContainerPolicies(), + coep_reporter->GetWeakPtr(), network::GetTestNetworkRestrictionsId()); auto fetch_client_settings_object = blink::mojom::FetchClientSettingsObject::New(); @@ -368,6 +366,29 @@ void SetUp() override { RenderViewHostImplTestHarness::SetUp(); } }; +TEST_F(DedicatedWorkerHostFactoryImplTest, + FactoryResetOnCrossDocumentNavigation) { + // Disable back/forward cache so the previous document is destroyed on + // navigation rather than being preserved. + web_contents()->GetController().GetBackForwardCache().DisableForTesting( + BackForwardCache::TEST_REQUIRES_NO_CACHING); + + const GURL kUrlA("http://a.example.com/"); + const GURL kUrlB("http://b.example.com/"); + + NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(), kUrlA); + + mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory; + static_cast<RenderFrameHostImpl*>(web_contents()->GetPrimaryMainFrame()) + ->CreateDedicatedWorkerHostFactory(factory.BindNewPipeAndPassReceiver()); + factory.FlushForTesting(); + ASSERT_TRUE(factory.is_connected()); + + NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(), kUrlB); + factory.FlushForTesting(); + EXPECT_FALSE(factory.is_connected()); +} + TEST_F(DedicatedWorkerHostFactoryImplTest, CrossOriginScriptOriginCheck) { url::ScopedSchemeRegistryForTests scoped_registry; url::AddStandardScheme("isolated-app", url::SCHEME_WITH_HOST); @@ -401,7 +422,8 @@ base::UnguessableToken::Create(), net::NetworkAnonymizationKey()); - return std::make_unique<DedicatedWorkerHostFactoryImpl>( + DedicatedWorkerHostFactoryImpl::Create( + *creator_rfh, factory.BindNewPipeAndPassReceiver(), creator_rfh->GetProcess()->GetID(), static_cast<RenderFrameHostImpl*>(creator_rfh)->GetGlobalId(), static_cast<RenderFrameHostImpl*>(creator_rfh) @@ -440,9 +462,7 @@ features::kEnforceDedicatedWorkerSameOriginCheck); mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory; - auto factory_impl = create_factory(factory, kIwaOriginA); - mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver( - factory_impl.get(), factory.BindNewPipeAndPassReceiver()); + create_factory(factory, kIwaOriginA); mojo::test::BadMessageObserver bad_message_observer; start_script_load(factory, kIwaAppB); @@ -458,9 +478,7 @@ features::kEnforceDedicatedWorkerSameOriginCheck); mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory; - auto factory_impl = create_factory(factory, kIwaOriginA); - mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver( - factory_impl.get(), factory.BindNewPipeAndPassReceiver()); + create_factory(factory, kIwaOriginA); mojo::test::BadMessageObserver bad_message_observer; start_script_load(factory, kIwaAppB); @@ -477,9 +495,7 @@ features::kEnforceDedicatedWorkerSameOriginCheck); mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory; - auto factory_impl = create_factory(factory, kExtOriginA); - mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver( - factory_impl.get(), factory.BindNewPipeAndPassReceiver()); + create_factory(factory, kExtOriginA); mojo::test::BadMessageObserver bad_message_observer; // Cross-origin load (even to https) should be blocked for extensions now. @@ -497,9 +513,7 @@ features::kEnforceDedicatedWorkerSameOriginCheck); mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory; - auto factory_impl = create_factory(factory, kIwaOriginA); - mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver( - factory_impl.get(), factory.BindNewPipeAndPassReceiver()); + create_factory(factory, kIwaOriginA); mojo::test::BadMessageObserver bad_message_observer; start_script_load(factory, kIwaAppA); @@ -516,9 +530,7 @@ features::kEnforceDedicatedWorkerSameOriginCheck); mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory; - auto factory_impl = create_factory(factory, kIwaOriginA); - mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver( - factory_impl.get(), factory.BindNewPipeAndPassReceiver()); + create_factory(factory, kIwaOriginA); mojo::test::BadMessageObserver bad_message_observer; start_script_load(factory, GURL("data:text/javascript,console.log('hi')")); @@ -553,7 +565,8 @@ base::UnguessableToken::Create(), net::NetworkAnonymizationKey()); - return std::make_unique<DedicatedWorkerHostFactoryImpl>( + DedicatedWorkerHostFactoryImpl::Create( + *opaque_rfh, factory.BindNewPipeAndPassReceiver(), opaque_rfh->GetProcess()->GetID(), static_cast<RenderFrameHostImpl*>(opaque_rfh)->GetGlobalId(), static_cast<RenderFrameHostImpl*>(opaque_rfh) @@ -567,9 +580,7 @@ }; mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory; - auto factory_impl = create_opaque_factory(factory); - mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver( - factory_impl.get(), factory.BindNewPipeAndPassReceiver()); + create_opaque_factory(factory); mojo::test::BadMessageObserver bad_message_observer; // Attempt to load a script that would normally be same-origin to the
Regression Test / PoC
diff --git a/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc b/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc
index 4b99649..7249859 100644
--- a/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc
+++ b/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc
@@ -18,6 +18,7 @@
#include "content/browser/worker_host/dedicated_worker_host.h"
#include "content/browser/worker_host/dedicated_worker_host_factory_impl.h"
#include "content/common/content_navigation_policy.h"
+#include "content/public/browser/back_forward_cache.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_features.h"
#include "content/public/test/navigation_simulator.h"
@@ -27,7 +28,6 @@
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
#include "mojo/public/cpp/bindings/remote.h"
-#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/test_support/test_utils.h"
#include "net/base/isolation_info.h"
#include "net/storage_access_api/status.h"
@@ -62,17 +62,15 @@
GURL(), std::nullopt, std::nullopt, base::UnguessableToken::Create(),
net::NetworkAnonymizationKey());
- mojo::MakeSelfOwnedReceiver(
- std::make_unique<DedicatedWorkerHostFactoryImpl>(
- worker_process_id, /*creator=*/render_frame_host_id,
- RenderFrameHostImpl::FromID(render_frame_host_id)
- ->GetWeakDocumentPtr(),
- blink::StorageKey::CreateFirstParty(origin),
- net::IsolationInfo::CreateTransient(/*nonce=*/std::nullopt),
- network::mojom::ClientSecurityState::New(),
- PolicyContainerPolicies(), coep_reporter->GetWeakPtr(),
- network::GetTestNetworkRestrictionsId()),
- factory_.BindNewPipeAndPassReceiver());
+ DedicatedWorkerHostFactoryImpl::Create(
+ *RenderFrameHostImpl::FromID(render_frame_host_id),
+ factory_.BindNewPipeAndPassReceiver(), worker_process_id,
+ /*creator=*/render_frame_host_id,
+ RenderFrameHostImpl::FromID(render_frame_host_id)->GetWeakDocumentPtr(),
+ blink::StorageKey::CreateFirstParty(origin),
+ net::IsolationInfo::CreateTransient(/*nonce=*/std::nullopt),
+ network::mojom::ClientSecurityState::New(), PolicyContainerPolicies(),
+ coep_reporter->GetWeakPtr(), network::GetTestNetworkRestrictionsId());
auto fetch_client_settings_object =
blink::mojom::FetchClientSettingsObject::New();
@@ -368,6 +366,29 @@
void SetUp() override { RenderViewHostImplTestHarness::SetUp(); }
};
+TEST_F(DedicatedWorkerHostFactoryImplTest,
+ FactoryResetOnCrossDocumentNavigation) {
+ // Disable back/forward cache so the previous document is destroyed on
+ // navigation rather than being preserved.
+ web_contents()->GetController().GetBackForwardCache().DisableForTesting(
+ BackForwardCache::TEST_REQUIRES_NO_CACHING);
+
+ const GURL kUrlA("http://a.example.com/");
+ const GURL kUrlB("http://b.example.com/");
+
+ NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(), kUrlA);
+
+ mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory;
+ static_cast<RenderFrameHostImpl*>(web_contents()->GetPrimaryMainFrame())
+ ->CreateDedicatedWorkerHostFactory(factory.BindNewPipeAndPassReceiver());
+ factory.FlushForTesting();
+ ASSERT_TRUE(factory.is_connected());
+
+ NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(), kUrlB);
+ factory.FlushForTesting();
+ EXPECT_FALSE(factory.is_connected());
+}
+
TEST_F(DedicatedWorkerHostFactoryImplTest, CrossOriginScriptOriginCheck) {
url::ScopedSchemeRegistryForTests scoped_registry;
url::AddStandardScheme("isolated-app", url::SCHEME_WITH_HOST);
@@ -401,7 +422,8 @@
base::UnguessableToken::Create(),
net::NetworkAnonymizationKey());
- return std::make_unique<DedicatedWorkerHostFactoryImpl>(
+ DedicatedWorkerHostFactoryImpl::Create(
+ *creator_rfh, factory.BindNewPipeAndPassReceiver(),
creator_rfh->GetProcess()->GetID(),
static_cast<RenderFrameHostImpl*>(creator_rfh)->GetGlobalId(),
static_cast<RenderFrameHostImpl*>(creator_rfh)
@@ -440,9 +462,7 @@
features::kEnforceDedicatedWorkerSameOriginCheck);
mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory;
- auto factory_impl = create_factory(factory, kIwaOriginA);
- mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver(
- factory_impl.get(), factory.BindNewPipeAndPassReceiver());
+ create_factory(factory, kIwaOriginA);
mojo::test::BadMessageObserver bad_message_observer;
start_script_load(factory, kIwaAppB);
@@ -458,9 +478,7 @@
features::kEnforceDedicatedWorkerSameOriginCheck);
mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory;
- auto factory_impl = create_factory(factory, kIwaOriginA);
- mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver(
- factory_impl.get(), factory.BindNewPipeAndPassReceiver());
+ create_factory(factory, kIwaOriginA);
mojo::test::BadMessageObserver bad_message_observer;
start_script_load(factory, kIwaAppB);
@@ -477,9 +495,7 @@
features::kEnforceDedicatedWorkerSameOriginCheck);
mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory;
- auto factory_impl = create_factory(factory, kExtOriginA);
- mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver(
- factory_impl.get(), factory.BindNewPipeAndPassReceiver());
+ create_factory(factory, kExtOriginA);
mojo::test::BadMessageObserver bad_message_observer;
// Cross-origin load (even to https) should be blocked for extensions now.
@@ -497,9 +513,7 @@
features::kEnforceDedicatedWorkerSameOriginCheck);
mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory;
- auto factory_impl = create_factory(factory, kIwaOriginA);
- mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver(
- factory_impl.get(), factory.BindNewPipeAndPassReceiver());
+ create_factory(factory, kIwaOriginA);
mojo::test::BadMessageObserver bad_message_observer;
start_script_load(factory, kIwaAppA);
@@ -516,9 +530,7 @@
features::kEnforceDedicatedWorkerSameOriginCheck);
mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory;
- auto factory_impl = create_factory(factory, kIwaOriginA);
- mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver(
- factory_impl.get(), factory.BindNewPipeAndPassReceiver());
+ create_factory(factory, kIwaOriginA);
mojo::test::BadMessageObserver bad_message_observer;
start_script_load(factory, GURL("data:text/javascript,console.log('hi')"));
@@ -553,7 +565,8 @@
base::UnguessableToken::Create(),
net::NetworkAnonymizationKey());
- return std::make_unique<DedicatedWorkerHostFactoryImpl>(
+ DedicatedWorkerHostFactoryImpl::Create(
+ *opaque_rfh, factory.BindNewPipeAndPassReceiver(),
opaque_rfh->GetProcess()->GetID(),
static_cast<RenderFrameHostImpl*>(opaque_rfh)->GetGlobalId(),
static_cast<RenderFrameHostImpl*>(opaque_rfh)
@@ -567,9 +580,7 @@
};
mojo::Remote<blink::mojom::DedicatedWorkerHostFactory> factory;
- auto factory_impl = create_opaque_factory(factory);
- mojo::Receiver<blink::mojom::DedicatedWorkerHostFactory> receiver(
- factory_impl.get(), factory.BindNewPipeAndPassReceiver());
+ create_opaque_factory(factory);
mojo::test::BadMessageObserver bad_message_observer;
// Attempt to load a script that would normally be same-origin to the