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 <chikamune@chromium.org>
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 <chikamune@chromium.org>
Reviewed-by: Rakina Zata Amni <rakina@chromium.org>
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