Chrome · Media
CVE-2026-106190
UAF in Media
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifthird_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc |
modified | |
TEST_Fthird_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc |
modified |
Files Changed
third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.ccthird_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
Patch
From 61ef27611dc69f16b6fe899c8b90a80330ac88df Mon Sep 17 00:00:00 2001
From: Dale Curtis <dalecurtis@chromium.org>
Date: Wed, 30 Sep 2026 10:29:21 -0700
Subject: [PATCH] Fix bugs in ResourceMultiBufferDataProvider::DidReceiveResponse
In ResourceMultiBufferDataProvider::DidReceiveResponse(), check a
WeakPtr across old_url_data->RedirectTo(destination_url_data).
RedirectTo() synchronously notifies MultiBufferDataSource, which can
reset reader_ and delete the active ResourceMultiBufferDataProvider when
the redirect destination already has sufficient cached data and
cancel_on_defer_ is set.
Fixed: 566824998
Change-Id: I193b4ffd5427aa0673773a5ec0747adad7fc3953
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8488169
Commit-Queue: Thomas Guilbert <tguilbert@chromium.org>
Auto-Submit: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: Thomas Guilbert <tguilbert@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1708261}
---
diff --git a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
index bac246c..778dc39 100644
--- a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
+++ b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
@@ -382,7 +382,11 @@
// Call callback to let upstream users know about the transfer.
// This will merge the data from the two multibuffers and
// cause clients to start using the new UrlData.
+ auto weak_this = weak_factory_.GetWeakPtr();
old_url_data->RedirectTo(destination_url_data);
+ if (!weak_this) {
+ return; // "this" may be deleted now.
+ }
}
if (do_fail) {
diff --git a/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc b/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc
index 03aabf4..b7883a3 100644
--- a/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc
+++ b/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc
@@ -2242,4 +2242,50 @@
UrlData::kNormal));
}
+TEST_F(MultiBufferDataSourceTest, Http_RedirectToCachedUrlWithStopPreloading) {
+ // Populate the cache for `kHttpDifferentPathUrl` with 2 blocks (64KB), which
+ // exceeds the METADATA preload_high threshold (48KB).
+ Initialize(kHttpDifferentPathUrl, true);
+ EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length()));
+ Respond(response_generator_->Generate206(0));
+ EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize));
+ ReceiveData(kDataSize);
+ EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 2));
+ ReceiveData(kDataSize);
+ Stop();
+
+ // Initialize a new data source for `kHttpUrl` with METADATA preload and
+ // receive less than one full block (1024 bytes) so `init_cb_` stays pending
+ // while `loading_` becomes true. Calling `StopPreloading()` then sets
+ // `cancel_on_defer_` without resetting `reader_`. When the partial-data retry
+ // redirects to the already-cached `kHttpDifferentPathUrl`, `RedirectTo()`
+ // synchronously resets `reader_` and deletes
+ // `ResourceMultiBufferDataProvider` while `DidReceiveResponse` is still on
+ // the stack.
+ set_preload(MultiBufferDataSource::METADATA);
+ Initialize(kHttpUrl, false);
+ Respond(response_generator_->Generate206(0));
+ EXPECT_CALL(host_, AddBufferedByteRange(0, 1024));
+ ReceiveData(1024);
+ data_source_->StopPreloading();
+ ASSERT_TRUE(active_loader());
+
+ base::RunLoop run_loop;
+ data_provider()->DidFinishLoading();
+ data_provider()->RunOnStart(run_loop.QuitClosure());
+ run_loop.Run();
+
+ WebURL redir_url{KURL(kHttpDifferentPathUrl)};
+ WebURLResponse redirect_response{KURL(kHttpUrl)};
+ redirect_response.SetHttpStatusCode(307);
+ data_provider()->WillFollowRedirect(redir_url, redirect_response);
+
+ EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 2))
+ .Times(testing::AtLeast(1));
+ Respond(response_generator_->Generate206(0));
+
+ EXPECT_FALSE(loading());
+ Stop();
+}
+
} // namespace blink
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc b/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc
index 03aabf4..b7883a3 100644
--- a/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc
+++ b/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc
@@ -2242,4 +2242,50 @@
UrlData::kNormal));
}
+TEST_F(MultiBufferDataSourceTest, Http_RedirectToCachedUrlWithStopPreloading) {
+ // Populate the cache for `kHttpDifferentPathUrl` with 2 blocks (64KB), which
+ // exceeds the METADATA preload_high threshold (48KB).
+ Initialize(kHttpDifferentPathUrl, true);
+ EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length()));
+ Respond(response_generator_->Generate206(0));
+ EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize));
+ ReceiveData(kDataSize);
+ EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 2));
+ ReceiveData(kDataSize);
+ Stop();
+
+ // Initialize a new data source for `kHttpUrl` with METADATA preload and
+ // receive less than one full block (1024 bytes) so `init_cb_` stays pending
+ // while `loading_` becomes true. Calling `StopPreloading()` then sets
+ // `cancel_on_defer_` without resetting `reader_`. When the partial-data retry
+ // redirects to the already-cached `kHttpDifferentPathUrl`, `RedirectTo()`
+ // synchronously resets `reader_` and deletes
+ // `ResourceMultiBufferDataProvider` while `DidReceiveResponse` is still on
+ // the stack.
+ set_preload(MultiBufferDataSource::METADATA);
+ Initialize(kHttpUrl, false);
+ Respond(response_generator_->Generate206(0));
+ EXPECT_CALL(host_, AddBufferedByteRange(0, 1024));
+ ReceiveData(1024);
+ data_source_->StopPreloading();
+ ASSERT_TRUE(active_loader());
+
+ base::RunLoop run_loop;
+ data_provider()->DidFinishLoading();
+ data_provider()->RunOnStart(run_loop.QuitClosure());
+ run_loop.Run();
+
+ WebURL redir_url{KURL(kHttpDifferentPathUrl)};
+ WebURLResponse redirect_response{KURL(kHttpUrl)};
+ redirect_response.SetHttpStatusCode(307);
+ data_provider()->WillFollowRedirect(redir_url, redirect_response);
+
+ EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 2))
+ .Times(testing::AtLeast(1));
+ Respond(response_generator_->Generate206(0));
+
+ EXPECT_FALSE(loading());
+ Stop();
+}
+
} // namespace blink
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