High chrome UAF 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Media
DescriptionUse after free in Media
ComponentMedia
Bug ClassUAF
Tracker568037533
Fix commitccb98073b620 (chromium/src) +45/-1
CISA KEVNot listed
Creditedweihengqiuu
Disclosed2026-10-13

Changed Functions

FunctionChangeNotes
if
third_party/blink/renderer/platform/media/multi_buffer_data_source.cc
modified
TEST_F
third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc
modified

Files Changed

  • third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc
  • third_party/blink/renderer/platform/media/multi_buffer_data_source.cc
  • third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
From ccb98073b6207c8c4c5e685ee7a7ca95f8e55595 Mon Sep 17 00:00:00 2001
From: Dale Curtis <[email protected]>
Date: Mon, 05 Oct 2026 16:59:47 -0700
Subject: [PATCH] Fix bugs when ResourceMultiBufferDataProvider::Start fails

When MultiBuffer::AddReader calls ResourceMultiBuffer::CreateWriter,
ResourceMultiBufferDataProvider::Start is invoked synchronously. If
UrlIndex has already been destroyed, Start() previously called
url_data_->Fail() synchronously, which runs
MultiBufferDataSource::OnRedirected(nullptr) -> StopLoader() and
destroys the MultiBufferReader while MultiBuffer::AddReader and
MultiBufferReader::UpdateInternalState are still on the stack.

Post UrlData::Fail asynchronously via task_runner_->PostTask, matching
the existing asynchronous Terminate() path in Start(). Also check
stop_signal_received_ with a scoped lock in
MultiBufferDataSource::SetBitrateTask to match the other posted
MultiBufferDataSource tasks.

Fixed: 568037533
Change-Id: I47984f21cc74c54da8cae6ada583a7fac24ccb51
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8497446
Commit-Queue: Dale Curtis <[email protected]>
Reviewed-by: Eugene Zemtsov <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1711814}
---
diff --git a/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc b/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc
index 5d2150e..a6958912 100644
--- a/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc
+++ b/third_party/blink/renderer/platform/media/multi_buffer_data_source.cc
@@ -580,6 +580,12 @@
 
 void MultiBufferDataSource::SetBitrateTask(int bitrate) {
   DCHECK(render_task_runner_->BelongsToCurrentThread());
+  {
+    base::AutoLock auto_lock(lock_);
+    if (stop_signal_received_) {
+      return;
+    }
+  }
 
   bitrate_ = bitrate;
   UpdateBufferSizes();
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 89ad4ff..0f85bd7 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
@@ -149,7 +149,8 @@
     active_loader_ = url_index->fetch_context()->CreateUrlLoader(options);
     active_loader_->LoadAsynchronously(request, this);
   } else {
-    url_data_->Fail();
+    task_runner_->PostTask(FROM_HERE,
+                           blink::BindOnce(&UrlData::Fail, url_data_));
   }
 }
 
diff --git a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc
index ad01eeb..8c857d2f 100644
--- a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc
+++ b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc
@@ -529,4 +529,41 @@
   loader->DidReceiveData(data_str);
 }
 
+TEST_F(ResourceMultiBufferDataProviderTest, DestructedUrlIndexStartViaReader) {
+  url_index_ = std::make_unique<UrlIndex>(
+      &fetch_context_, task_environment_.GetMainThreadTaskRunner());
+  url_ = KURL(kHttpUrl);
+  url_data_ =
+      url_index_->GetByUrl(url_, UrlData::CORS_UNSPECIFIED, UrlData::kNormal);
+
+  std::unique_ptr<MultiBufferReader> reader;
+  url_data_->OnRedirect(blink::BindOnce(
+      [](std::unique_ptr<MultiBufferReader>* reader_ptr,
+         const scoped_refptr<UrlData>& destination) {
+        EXPECT_FALSE(destination);
+        reader_ptr->reset();
+      },
+      Unretained(&reader)));
+
+  url_index_.reset();
+
+  // Creating a reader and calling SetPreload() invokes
+  // MultiBufferReader::UpdateInternalState() -> MultiBuffer::AddReader() ->
+  // ResourceMultiBuffer::CreateWriter() ->
+  // ResourceMultiBufferDataProvider::Start(). When `url_index_` is already
+  // destroyed, `Start()` must not synchronously run `url_data_->Fail()` and
+  // destroy `reader` while `AddReader()` and `UpdateInternalState()` are still
+  // on the stack.
+  reader = std::make_unique<MultiBufferReader>(
+      url_data_->multibuffer(), 0, 1024 * 1024,
+      /*is_client_audio_element=*/false, base::DoNothing(),
+      task_environment_.GetMainThreadTaskRunner());
+  reader->SetPinRange(0, 1024 * 1024);
+  reader->SetPreload(kDataSize, kDataSize);
+  ASSERT_TRUE(reader);
+
+  task_environment_.FastForwardUntilNoTasksRemain();
+  EXPECT_FALSE(reader);
+}
+
 }  // namespace blink
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc
index ad01eeb..8c857d2f 100644
--- a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc
+++ b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc
@@ -529,4 +529,41 @@
   loader->DidReceiveData(data_str);
 }
 
+TEST_F(ResourceMultiBufferDataProviderTest, DestructedUrlIndexStartViaReader) {
+  url_index_ = std::make_unique<UrlIndex>(
+      &fetch_context_, task_environment_.GetMainThreadTaskRunner());
+  url_ = KURL(kHttpUrl);
+  url_data_ =
+      url_index_->GetByUrl(url_, UrlData::CORS_UNSPECIFIED, UrlData::kNormal);
+
+  std::unique_ptr<MultiBufferReader> reader;
+  url_data_->OnRedirect(blink::BindOnce(
+      [](std::unique_ptr<MultiBufferReader>* reader_ptr,
+         const scoped_refptr<UrlData>& destination) {
+        EXPECT_FALSE(destination);
+        reader_ptr->reset();
+      },
+      Unretained(&reader)));
+
+  url_index_.reset();
+
+  // Creating a reader and calling SetPreload() invokes
+  // MultiBufferReader::UpdateInternalState() -> MultiBuffer::AddReader() ->
+  // ResourceMultiBuffer::CreateWriter() ->
+  // ResourceMultiBufferDataProvider::Start(). When `url_index_` is already
+  // destroyed, `Start()` must not synchronously run `url_data_->Fail()` and
+  // destroy `reader` while `AddReader()` and `UpdateInternalState()` are still
+  // on the stack.
+  reader = std::make_unique<MultiBufferReader>(
+      url_data_->multibuffer(), 0, 1024 * 1024,
+      /*is_client_audio_element=*/false, base::DoNothing(),
+      task_environment_.GetMainThreadTaskRunner());
+  reader->SetPinRange(0, 1024 * 1024);
+  reader->SetPreload(kDataSize, kDataSize);
+  ASSERT_TRUE(reader);
+
+  task_environment_.FastForwardUntilNoTasksRemain();
+  EXPECT_FALSE(reader);
+}
+
 }  // 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.