Chrome · Workers
CVE-2026-113015
UAF in Workers
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifstorage/browser/blob/blob_url_registry.cc |
modified | |
ifstorage/browser/blob/blob_url_store_impl.cc |
modified | |
TEST_Fcontent/browser/worker_host/dedicated_worker_service_impl_unittest.cc |
modified | |
ifcontent/browser/worker_host/dedicated_worker_service_impl_unittest.cc |
modified | |
TEST_Fcontent/browser/worker_host/shared_worker_host_unittest.cc |
modified | |
TEST_Pstorage/browser/blob/blob_url_registry_unittest.cc |
modified |
Files Changed
storage/browser/blob/blob_url_registry.cccontent/browser/worker_host/shared_worker_host.ccstorage/browser/blob/blob_url_registry_unittest.cccontent/browser/worker_host/dedicated_worker_service_impl_unittest.ccstorage/browser/blob/blob_url_registry.hcontent/browser/worker_host/shared_worker_host_unittest.cccontent/browser/worker_host/dedicated_worker_host.ccstorage/browser/blob/blob_url_store_impl.cc
Patch
From ecb2d9f92d3f1db479c963524aab18b078bc8995 Mon Sep 17 00:00:00 2001 From: Minoru Chikamune <[email protected]> Date: Sat, 19 Sep 2026 05:23:15 -0700 Subject: [PATCH] Improve origin check and mapping validation in BlobUrlRegistry and worker hosts Ensure worker hosts only pass ALLOW_OPAQUE_ORIGIN_STORAGE_KEY_MISMATCH when the worker origin is opaque. In addition, prevent duplicate mappings in BlobUrlRegistry and clarify cross-origin status handling in BlobURLStoreImpl. TAG=agy CONV=3ae70192-2c92-4bb2-88d1-8cf469c4a0dc Fixed: 497408124 Change-Id: Ib2b78fb1103d1a36d77848971fd971c7d5b7be3b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8255371 Commit-Queue: Minoru Chikamune <[email protected]> Reviewed-by: Rakina Zata Amni <[email protected]> Cr-Commit-Position: refs/heads/main@{#1701383} --- diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc index 441374f..434dbf5 100644 --- a/content/browser/worker_host/dedicated_worker_host.cc +++ b/content/browser/worker_host/dedicated_worker_host.cc @@ -972,10 +972,12 @@ weak_factory_.GetWeakPtr()), !(GetContentClient()->browser()->IsBlobUrlPartitioningEnabled( GetProcessHost()->GetBrowserContext())), - base::FeatureList::IsEnabled(blink::features::kDataUrlWorkerOpaqueOrigin) - ? storage::BlobURLValidityCheckBehavior::DEFAULT - : storage::BlobURLValidityCheckBehavior:: - ALLOW_OPAQUE_ORIGIN_STORAGE_KEY_MISMATCH); + (!base::FeatureList::IsEnabled( + blink::features::kDataUrlWorkerOpaqueOrigin) && + renderer_origin_.opaque()) + ? storage::BlobURLValidityCheckBehavior:: + ALLOW_OPAQUE_ORIGIN_STORAGE_KEY_MISMATCH + : storage::BlobURLValidityCheckBehavior::DEFAULT); } void DedicatedWorkerHost::CreateCodeCacheHost( diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc index 98708424..aec63a1b9 100644 --- a/content/browser/worker_host/shared_worker_host.cc +++ b/content/browser/worker_host/shared_worker_host.cc @@ -780,8 +780,13 @@ auto* storage_partition_impl = GetStoragePartitionImpl(); + // Pass `instance().renderer_origin()` rather than + // `instance().worker_storage_key().origin()` because when + // `kDataUrlWorkerOpaqueOrigin` is disabled, a data: URL shared worker's + // `worker_storage_key_.origin()` remains non-opaque while its renderer-side + // origin is opaque. We must use the origin actually used by the renderer. storage_partition_impl->GetBlobUrlRegistry()->AddReceiver( - GetWorkerStorageKey(), instance().worker_storage_key().origin(), + GetWorkerStorageKey(), instance().renderer_origin(), GetProcessHost()->GetDeprecatedID(), std::move(receiver), /*context_type_for_debugging=*/"Shared Worker", base::BindRepeating( @@ -796,10 +801,12 @@ base::BindRepeating([]() -> bool { return false; }), !(GetContentClient()->browser()->IsBlobUrlPartitioningEnabled( GetProcessHost()->GetBrowserContext())), - base::FeatureList::IsEnabled(blink::features::kDataUrlWorkerOpaqueOrigin) - ? storage::BlobURLValidityCheckBehavior::DEFAULT - : storage::BlobURLValidityCheckBehavior:: - ALLOW_OPAQUE_ORIGIN_STORAGE_KEY_MISMATCH); + (!base::FeatureList::IsEnabled( + blink::features::kDataUrlWorkerOpaqueOrigin) && + instance().renderer_origin().opaque()) + ? storage::BlobURLValidityCheckBehavior:: + ALLOW_OPAQUE_ORIGIN_STORAGE_KEY_MISMATCH + : storage::BlobURLValidityCheckBehavior::DEFAULT); } void SharedWorkerHost::CreateBucketManagerHost( diff --git a/storage/browser/blob/blob_url_registry.cc b/storage/browser/blob/blob_url_registry.cc index b5bd1aa..c3ebb81 100644 --- a/storage/browser/blob/blob_url_registry.cc +++ b/storage/browser/blob/blob_url_registry.cc @@ -96,8 +96,8 @@ int render_process_host_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!BlobUrlUtils::UrlHasFragment(blob_url)); - if (IsUrlMapped(blob_url, storage_key) == - BlobUrlRegistry::MappingStatus::kIsMapped) { + if (IsUrlMapped(blob_url, storage_key) != + BlobUrlRegistry::MappingStatus::kNotMappedOther) { return false; } BlobUrlData data; @@ -176,7 +176,7 @@ // A fallback_ check isn't needed because a given Blob URL will either be // registered in this BlobUrlRegistry or registered in the fallback // BlobUrlRegistry but not both. - return BlobUrlRegistry::MappingStatus::kNotMappedOther; + return BlobUrlRegistry::MappingStatus::kNotMappedCrossOrigin; } if (fallback_) { return fallback_->IsUrlMapped(blob_url, storage_key); diff --git a/storage/browser/blob/blob_url_registry.h b/storage/browser/blob/blob_url_registry.h index 37b78a5..e0273ae7 100644 --- a/storage/browser/blob/blob_url_registry.h +++ b/storage/browser/blob/blob_url_registry.h @@ -42,6 +42,9 @@ // This refers to either a first-party or different third-party context // attempting to access a Blob URL created in a third-party context. kNotMappedCrossPartitionSameOriginAccessThirdPartyBlobURL, + // This refers to an attempt to access a Blob URL created in a context with + // a different origin. + kNotMappedCrossOrigin, kNotMappedOther }; diff --git a/storage/browser/blob/blob_url_store_impl.cc b/storage/browser/blob/blob_url_store_impl.cc index b8e434ca..5993d5c 100644 --- a/storage/browser/blob/blob_url_store_impl.cc +++ b/storage/browser/blob/blob_url_store_impl.cc @@ -173,8 +173,8 @@ // mime types (which result in a resource load for the URL as well) don't get // blocked by partitioning. For more information, see crbug.com/426787402. bool is_top_level_blob_document_self_fetch = - top_level_blob_document_url_.has_value() && - top_level_blob_document_url_.value() == url; + top_level_blob_document_url_.has_value() && + top_level_blob_document_url_.value() == url; if (!is_top_level_blob_document_self_fetch) { const BlobUrlRegistry::MappingStatus mapping_status = 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 3f5596a..d4e3f17e 100644 --- a/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc +++ b/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc @@ -40,6 +40,7 @@ #include "third_party/blink/public/common/tokens/tokens.h" #include "third_party/blink/public/common/tokens/tokens_mojom_traits.h" #include "third_party/blink/public/common/web_preferences/web_preferences.h" +#include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h" #include "third_party/blink/public/mojom/loader/fetch_client_settings_object.mojom.h" #include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker_container.mojom.h" @@ -774,4 +775,81 @@ net::StorageAccessApiStatus::kAccessViaAPI); } +// Tests that DedicatedWorkerHost::CreateBlobUrlStoreProvider successfully binds +// the BlobURLStore receiver when the worker has a standard non-opaque origin. +TEST_F(DedicatedWorkerServiceImplTest, CreateBlobUrlStoreProvider) { + TestDedicatedWorkerServiceObserver observer; + base::ScopedObservation<DedicatedWorkerService, + DedicatedWorkerService::Observer> + scoped_observation(&observer); + scoped_observation.Observe(GetDedicatedWorkerService()); + + const GURL kUrl("http://example.com/"); + std::unique_ptr<TestWebContents> web_contents = CreateWebContents(kUrl); + TestRenderFrameHost* render_frame_host = web_contents->GetPrimaryMainFrame(); + const ChildProcessId render_process_host_id = + render_frame_host->GetProcess()->GetID(); + const auto origin = url::Origin::Create(kUrl); + auto mock_dedicated_worker = std::make_unique<MockDedicatedWorker>( + render_process_host_id, render_frame_host->GetGlobalId(), origin); + observer.RunUntilWorkerEvent(); + EXPECT_EQ(observer.dedicated_worker_infos().size(), 1u); + if (observer.dedicated_worker_infos().empty()) { + return; + } + const blink::DedicatedWorkerToken worker_token = + observer.dedicated_worker_infos().begin()->first; + DedicatedWorkerHost* host = + static_cast<DedicatedWorkerServiceImpl*>(GetDedicatedWorkerService()) + ->GetDedicatedWorkerHostFromToken(worker_token); + EXPECT_TRUE(host); + if (!host) { + return; + } + + // Verify that the worker host can create a BlobURLStore provider. + mojo::Remote<blink::mojom::BlobURLStore> remote; + host->CreateBlobUrlStoreProvider(remote.BindNewPipeAndPassReceiver()); + EXPECT_TRUE(remote.is_bound()); +} + +// Tests that DedicatedWorkerHost::CreateBlobUrlStoreProvider successfully binds +// the BlobURLStore receiver when the worker has an opaque origin (e.g. data: +// URL workers). +TEST_F(DedicatedWorkerServiceImplTest, CreateBlobUrlStoreProviderOpaqueOrigin) { + TestDedicatedWorkerServiceObserver observer; + base::ScopedObservation<DedicatedWorkerService, + DedicatedWorkerService::Observer> + scoped_observation(&observer); + scoped_observation.Observe(GetDedicatedWorkerService()); + + const GURL kUrl("http://example.com/"); + std::unique_ptr<TestWebContents> web_contents = CreateWebContents(kUrl); + TestRenderFrameHost* render_frame_host = web_contents->GetPrimaryMainFrame(); + const ChildProcessId render_process_host_id = + render_frame_host->GetProcess()->GetID(); + const auto origin = url::Origin(); + auto mock_dedicated_worker = std::make_unique<MockDedicatedWorker>( + render_process_host_id, render_frame_host->GetGlobalId(), origin); + observer.RunUntilWorkerEvent(); + EXPECT_EQ(observer.dedicated_worker_infos().size(), 1u); + if (observer.dedicated_worker_infos().empty()) { + return; + } + const blink::DedicatedWorkerToken worker_token = + observer.dedicated_worker_infos().begin()->first; + DedicatedWorkerHost* host = + static_cast<DedicatedWorkerServiceImpl*>(GetDedicatedWorkerService()) + ->GetDedicatedWorkerHostFromToken(worker_token); + EXPECT_TRUE(host); + if (!host) { + return; + } + + // Verify that the worker host with an opaque origin can create a + // BlobURLStore provider. + mojo::Remote<blink::mojom::BlobURLStore> remote; + host->CreateBlobUrlStoreProvider(remote.BindNewPipeAndPassReceiver()); + EXPECT_TRUE(remote.is_bound()); +} } // namespace content diff --git a/content/browser/worker_host/shared_worker_host_unittest.cc b/content/browser/worker_host/shared_worker_host_unittest.cc index 932f3ba..193b9ba 100644 --- a/content/browser/worker_host/shared_worker_host_unittest.cc +++ b/content/browser/worker_host/shared_worker_host_unittest.cc @@ -46,6 +46,7 @@ #include "third_party/blink/public/common/messaging/message_port_channel.h" #include "third_party/blink/public/common/messaging/message_port_descriptor.h" #include "third_party/blink/public/common/storage_key/storage_key.h" +#include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h" #include "third_party/blink/public/mojom/worker/shared_worker_exception_details.mojom.h" #include "url/origin.h" @@ -420,6 +421,36 @@ EXPECT_FALSE(params->isolation_info.nonce().has_value()); } +TEST_F(SharedWorkerHostTest, CreateBlobUrlStoreProvider) { + base::WeakPtr<SharedWorkerHost> host = CreateHost(); + mojo::Remote<blink::mojom::BlobURLStore> remote; + host->CreateBlobUrlStoreProvider(remote.BindNewPipeAndPassReceiver()); + EXPECT_TRUE(remote.is_bound()); +} + +TEST_F(SharedWorkerHostTest, CreateBlobUrlStoreProviderOpaqueOrigin) { + const GURL kDataWorkerUrl("data:text/javascript,"); + blink::StorageKey creator_storage_key = + blink::StorageKey::CreateFirstParty(url::Origin()); + blink::StorageKey worker_storage_key = + blink::StorageKey::CreateFirstParty(url::Origin()); + url::Origin renderer_origin = url::Origin(); + SharedWorkerInstance instance( + kDataWorkerUrl, blink::mojom::ScriptType::kClassic, + network::mojom::CredentialsMode::kSameOrigin, "name", creator_storage_key, + worker_storage_key, renderer_origin, + blink::mojom::SharedWorkerCreationContextType::kSecure, + blink::mojom::SharedWorkerSameSiteCookies::kNone, + /*extended_lifetime=*/false); + auto host = std::make_unique<SharedWorkerHost>( + &service_, instance, site_instance_, + std::vector<network::mojom::ContentSecurityPolicyPtr>(), + base::MakeRefCounted<PolicyContainerHost>()); + mojo::Remote<blink::mojom::BlobURLStore> remote; + host->CreateBlobUrlStoreProvider(remote.BindNewPipeAndPassReceiver()); + EXPECT_TRUE(remote.is_bound()); +} + TEST_F(SharedWorkerHostTest, CreateNetworkFactoryParamsForSubresourcesWithNonce) { base::UnguessableToken nonce = base::UnguessableToken::Create(); diff --git a/storage/browser/blob/blob_url_registry_unittest.cc b/storage/browser/blob/blob_url_registry_unittest.cc index 2186f3f..49297a5 100644 --- a/storage/browser/blob/blob_url_registry_unittest.cc +++ b/storage/browser/blob/blob_url_registry_unittest.cc @@ -124,7 +124,7 @@ // Test using a storage key that doesn't correspond to the Blob URL. EXPECT_NE(storageKey1, storageKey2); EXPECT_EQ(registry.IsUrlMapped(kURL1, storageKey2), - BlobUrlRegistry::MappingStatus::kNotMappedOther); + BlobUrlRegistry::MappingStatus::kNotMappedCrossOrigin); EXPECT_FALSE(registry.RemoveUrlMapping(kURL1, storageKey2)); EXPECT_EQ(registry.IsUrlMapped(kURL1, storageKey1), BlobUrlRegistry::MappingStatus::kIsMapped); @@ -152,7 +152,7 @@ EXPECT_TRUE(registry.GetBlobFromUrl(kURL1)); EXPECT_EQ(registry.IsUrlMapped(kURL1, partitionedStorageKey2), - BlobUrlRegistry::MappingStatus::kNotMappedOther); + BlobUrlRegistry::MappingStatus::kNotMappedCrossOrigin); EXPECT_FALSE(registry.RemoveUrlMapping(kURL1, partitionedStorageKey2)); EXPECT_EQ(registry.IsUrlMapped(kURL1, partitionedStorageKey1), BlobUrlRegistry::MappingStatus::kIsMapped); @@ -161,6 +161,41 @@ EXPECT_EQ(0u, registry.url_count()); } +TEST_P(BlobUrlRegistryTestP, RejectDuplicateUrlMapping) { + base::test::SingleThreadTaskEnvironment task_environment_; + const std::string kBlobId1 = "Blob1"; + const std::string kBlobId2 = "Blob2"; + const GURL kURL1 = GURL("blob://Blob1"); + const blink::StorageKey storageKey1 = + blink::StorageKey::CreateFirstParty(url::Origin::Create(kURL1)); + const blink::StorageKey storageKey2 = blink::StorageKey::CreateFirstParty( + url::Origin::Create(GURL("blob://Blob2"))); + + FakeBlob blob1(kBlobId1); + FakeBlob blob2(kBlobId2); + + BlobUrlRegistry registry; + EXPECT_TRUE(registry.AddUrlMapping(kURL1, blob1.Clone(), storageKey1, + storageKey1.origin(), + /*render_process_host_id=*/0)); + + // Attempting to register the exact same URL with the same storage key + // should also be rejected. + EXPECT_FALSE(registry.AddUrlMapping(kURL1, blob1.Clone(), storageKey1, + storageKey1.origin(), + /*render_process_host_id=*/0)); + + // Attempting to register the exact same URL with a different storage key + // should be rejected to maintain mapping integrity. + EXPECT_FALSE(registry.AddUrlMapping(kURL1, blob2.Clone(), storageKey2, + storageKey2.origin(), + /*render_process_host_id=*/0)); + + EXPECT_EQ(registry.IsUrlMapped(kURL1, storageKey2), + BlobUrlRegistry::MappingStatus::kNotMappedCrossOrigin); + EXPECT_EQ(kBlobId1, UuidFromBlob(registry.GetBlobFromUrl(kURL1))); +} + INSTANTIATE_TEST_SUITE_P( BlobUrlRegistryTests, BlobUrlRegistryTestP,
Loading diff…
Regression Test / PoC
shipped with the fix
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 3f5596a..d4e3f17e 100644
--- a/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc
+++ b/content/browser/worker_host/dedicated_worker_service_impl_unittest.cc
@@ -40,6 +40,7 @@
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/common/tokens/tokens_mojom_traits.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
+#include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h"
#include "third_party/blink/public/mojom/loader/fetch_client_settings_object.mojom.h"
#include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_container.mojom.h"
@@ -774,4 +775,81 @@
net::StorageAccessApiStatus::kAccessViaAPI);
}
+// Tests that DedicatedWorkerHost::CreateBlobUrlStoreProvider successfully binds
+// the BlobURLStore receiver when the worker has a standard non-opaque origin.
+TEST_F(DedicatedWorkerServiceImplTest, CreateBlobUrlStoreProvider) {
+ TestDedicatedWorkerServiceObserver observer;
+ base::ScopedObservation<DedicatedWorkerService,
+ DedicatedWorkerService::Observer>
+ scoped_observation(&observer);
+ scoped_observation.Observe(GetDedicatedWorkerService());
+
+ const GURL kUrl("http://example.com/");
+ std::unique_ptr<TestWebContents> web_contents = CreateWebContents(kUrl);
+ TestRenderFrameHost* render_frame_host = web_contents->GetPrimaryMainFrame();
+ const ChildProcessId render_process_host_id =
+ render_frame_host->GetProcess()->GetID();
+ const auto origin = url::Origin::Create(kUrl);
+ auto mock_dedicated_worker = std::make_unique<MockDedicatedWorker>(
+ render_process_host_id, render_frame_host->GetGlobalId(), origin);
+ observer.RunUntilWorkerEvent();
+ EXPECT_EQ(observer.dedicated_worker_infos().size(), 1u);
+ if (observer.dedicated_worker_infos().empty()) {
+ return;
+ }
+ const blink::DedicatedWorkerToken worker_token =
+ observer.dedicated_worker_infos().begin()->first;
+ DedicatedWorkerHost* host =
+ static_cast<DedicatedWorkerServiceImpl*>(GetDedicatedWorkerService())
+ ->GetDedicatedWorkerHostFromToken(worker_token);
+ EXPECT_TRUE(host);
+ if (!host) {
+ return;
+ }
+
+ // Verify that the worker host can create a BlobURLStore provider.
+ mojo::Remote<blink::mojom::BlobURLStore> remote;
+ host->CreateBlobUrlStoreProvider(remote.BindNewPipeAndPassReceiver());
+ EXPECT_TRUE(remote.is_bound());
+}
+
+// Tests that DedicatedWorkerHost::CreateBlobUrlStoreProvider successfully binds
+// the BlobURLStore receiver when the worker has an opaque origin (e.g. data:
+// URL workers).
+TEST_F(DedicatedWorkerServiceImplTest, CreateBlobUrlStoreProviderOpaqueOrigin) {
+ TestDedicatedWorkerServiceObserver observer;
+ base::ScopedObservation<DedicatedWorkerService,
+ DedicatedWorkerService::Observer>
+ scoped_observation(&observer);
+ scoped_observation.Observe(GetDedicatedWorkerService());
+
+ const GURL kUrl("http://example.com/");
+ std::unique_ptr<TestWebContents> web_contents = CreateWebContents(kUrl);
+ TestRenderFrameHost* render_frame_host = web_contents->GetPrimaryMainFrame();
+ const ChildProcessId render_process_host_id =
+ render_frame_host->GetProcess()->GetID();
+ const auto origin = url::Origin();
+ auto mock_dedicated_worker = std::make_unique<MockDedicatedWorker>(
+ render_process_host_id, render_frame_host->GetGlobalId(), origin);
+ observer.RunUntilWorkerEvent();
+ EXPECT_EQ(observer.dedicated_worker_infos().size(), 1u);
+ if (observer.dedicated_worker_infos().empty()) {
+ return;
+ }
+ const blink::DedicatedWorkerToken worker_token =
+ observer.dedicated_worker_infos().begin()->first;
+ DedicatedWorkerHost* host =
+ static_cast<DedicatedWorkerServiceImpl*>(GetDedicatedWorkerService())
+ ->GetDedicatedWorkerHostFromToken(worker_token);
+ EXPECT_TRUE(host);
+ if (!host) {
+ return;
+ }
+
+ // Verify that the worker host with an opaque origin can create a
+ // BlobURLStore provider.
+ mojo::Remote<blink::mojom::BlobURLStore> remote;
+ host->CreateBlobUrlStoreProvider(remote.BindNewPipeAndPassReceiver());
+ EXPECT_TRUE(remote.is_bound());
+}
} // namespace content
diff --git a/content/browser/worker_host/shared_worker_host_unittest.cc b/content/browser/worker_host/shared_worker_host_unittest.cc
index 932f3ba..193b9ba 100644
--- a/content/browser/worker_host/shared_worker_host_unittest.cc
+++ b/content/browser/worker_host/shared_worker_host_unittest.cc
@@ -46,6 +46,7 @@
#include "third_party/blink/public/common/messaging/message_port_channel.h"
#include "third_party/blink/public/common/messaging/message_port_descriptor.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
+#include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h"
#include "third_party/blink/public/mojom/worker/shared_worker_exception_details.mojom.h"
#include "url/origin.h"
@@ -420,6 +421,36 @@
EXPECT_FALSE(params->isolation_info.nonce().has_value());
}
+TEST_F(SharedWorkerHostTest, CreateBlobUrlStoreProvider) {
+ base::WeakPtr<SharedWorkerHost> host = CreateHost();
+ mojo::Remote<blink::mojom::BlobURLStore> remote;
+ host->CreateBlobUrlStoreProvider(remote.BindNewPipeAndPassReceiver());
+ EXPECT_TRUE(remote.is_bound());
+}
+
+TEST_F(SharedWorkerHostTest, CreateBlobUrlStoreProviderOpaqueOrigin) {
+ const GURL kDataWorkerUrl("data:text/javascript,");
+ blink::StorageKey creator_storage_key =
+ blink::StorageKey::CreateFirstParty(url::Origin());
+ blink::StorageKey worker_storage_key =
+ blink::StorageKey::CreateFirstParty(url::Origin());
+ url::Origin renderer_origin = url::Origin();
+ SharedWorkerInstance instance(
+ kDataWorkerUrl, blink::mojom::ScriptType::kClassic,
+ network::mojom::CredentialsMode::kSameOrigin, "name", creator_storage_key,
+ worker_storage_key, renderer_origin,
+ blink::mojom::SharedWorkerCreationContextType::kSecure,
+ blink::mojom::SharedWorkerSameSiteCookies::kNone,
+ /*extended_lifetime=*/false);
+ auto host = std::make_unique<SharedWorkerHost>(
+ &service_, instance, site_instance_,
+ std::vector<network::mojom::ContentSecurityPolicyPtr>(),
+ base::MakeRefCounted<PolicyContainerHost>());
+ mojo::Remote<blink::mojom::BlobURLStore> remote;
+ host->CreateBlobUrlStoreProvider(remote.BindNewPipeAndPassReceiver());
+ EXPECT_TRUE(remote.is_bound());
+}
+
TEST_F(SharedWorkerHostTest,
CreateNetworkFactoryParamsForSubresourcesWithNonce) {
base::UnguessableToken nonce = base::UnguessableToken::Create();
diff --git a/storage/browser/blob/blob_url_registry_unittest.cc b/storage/browser/blob/blob_url_registry_unittest.cc
index 2186f3f..49297a5 100644
--- a/storage/browser/blob/blob_url_registry_unittest.cc
+++ b/storage/browser/blob/blob_url_registry_unittest.cc
@@ -124,7 +124,7 @@
// Test using a storage key that doesn't correspond to the Blob URL.
EXPECT_NE(storageKey1, storageKey2);
EXPECT_EQ(registry.IsUrlMapped(kURL1, storageKey2),
- BlobUrlRegistry::MappingStatus::kNotMappedOther);
+ BlobUrlRegistry::MappingStatus::kNotMappedCrossOrigin);
EXPECT_FALSE(registry.RemoveUrlMapping(kURL1, storageKey2));
EXPECT_EQ(registry.IsUrlMapped(kURL1, storageKey1),
BlobUrlRegistry::MappingStatus::kIsMapped);
@@ -152,7 +152,7 @@
EXPECT_TRUE(registry.GetBlobFromUrl(kURL1));
EXPECT_EQ(registry.IsUrlMapped(kURL1, partitionedStorageKey2),
- BlobUrlRegistry::MappingStatus::kNotMappedOther);
+ BlobUrlRegistry::MappingStatus::kNotMappedCrossOrigin);
EXPECT_FALSE(registry.RemoveUrlMapping(kURL1, partitionedStorageKey2));
EXPECT_EQ(registry.IsUrlMapped(kURL1, partitionedStorageKey1),
BlobUrlRegistry::MappingStatus::kIsMapped);
@@ -161,6 +161,41 @@
EXPECT_EQ(0u, registry.url_count());
}
+TEST_P(BlobUrlRegistryTestP, RejectDuplicateUrlMapping) {
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ const std::string kBlobId1 = "Blob1";
+ const std::string kBlobId2 = "Blob2";
+ const GURL kURL1 = GURL("blob://Blob1");
+ const blink::StorageKey storageKey1 =
+ blink::StorageKey::CreateFirstParty(url::Origin::Create(kURL1));
+ const blink::StorageKey storageKey2 = blink::StorageKey::CreateFirstParty(
+ url::Origin::Create(GURL("blob://Blob2")));
+
+ FakeBlob blob1(kBlobId1);
+ FakeBlob blob2(kBlobId2);
+
+ BlobUrlRegistry registry;
+ EXPECT_TRUE(registry.AddUrlMapping(kURL1, blob1.Clone(), storageKey1,
+ storageKey1.origin(),
+ /*render_process_host_id=*/0));
+
+ // Attempting to register the exact same URL with the same storage key
+ // should also be rejected.
+ EXPECT_FALSE(registry.AddUrlMapping(kURL1, blob1.Clone(), storageKey1,
+ storageKey1.origin(),
+ /*render_process_host_id=*/0));
+
+ // Attempting to register the exact same URL with a different storage key
+ // should be rejected to maintain mapping integrity.
+ EXPECT_FALSE(registry.AddUrlMapping(kURL1, blob2.Clone(), storageKey2,
+ storageKey2.origin(),
+ /*render_process_host_id=*/0));
+
+ EXPECT_EQ(registry.IsUrlMapped(kURL1, storageKey2),
+ BlobUrlRegistry::MappingStatus::kNotMappedCrossOrigin);
+ EXPECT_EQ(kBlobId1, UuidFromBlob(registry.GetBlobFromUrl(kURL1)));
+}
+
INSTANTIATE_TEST_SUITE_P(
BlobUrlRegistryTests,
BlobUrlRegistryTestP,
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page