cc17d3287018c1536b5a49193366887818a50e47 Fix RenderWidgetHostViewAura UAF during shutdown
The bug at a glance
The commit fixes a confirmed browser-process use-after-free: RenderWidgetHostViewAura never unsubscribed as its window’s FocusChangeObserver, so a focus-change delivered during teardown could dispatch to the freed view; real reentrant crashes were observed in Edge during popup teardown.
Web content can open and tear down a popup widget (e.g. a dropdown) and race a reentrant focus-loss notification, causing FocusController to look up the window’s observer and call into the already-deleted RenderWidgetHostViewAura in the privileged browser process.
Root cause
RenderWidgetHostViewAura registers itself as the aura focus-change observer of window_ but, in its Shutdown/destruction path, cleared other observers yet never removed the FocusChangeObserver property while window_ was still alive. If a focus change arrived reentrantly during destruction (e.g. from Widget::Hide() while a popup closes), FocusController fetched the window’s FocusChangeObserver, obtained the dangling pointer to the destroyed view, and invoked a method on freed memory. The fix calls aura::client::SetFocusChangeObserver(window_, nullptr) during teardown when window_ is valid, so no stale observer remains reachable.
Key code
Clear the window’s FocusChangeObserver during RWHVA teardown to prevent a dangling callback
window_observer_.reset();
if (window_) {
+ aura::client::SetFocusChangeObserver(window_, nullptr);
if (window_->GetHost())
window_->GetHost()->RemoveObserver(this);
Patch walkthrough
content/browser/renderer_host/render_widget_host_view_aura.cc— Adds SetFocusChangeObserver(window_, nullptr) in the teardown block (when window_ outlives the view) so FocusController cannot resolve the window to the freed RWHVA and call into it, closing the UAF.content/browser/renderer_host/render_widget_host_view_aura_browsertest.cc— Adds a browser test that opens a popup widget, destroys the RWHVA before its window, and asserts the FocusChangeObserver property is cleared by the time the window is destroyed, regression-guarding the fix.
Background
RenderWidgetHostViewAura (RWHVA) — Browser-process view object backing a renderer widget on the Aura windowing platform.
FocusController / FocusChangeObserver — Aura mechanism that notifies a window’s registered observer when focus moves between windows.
Popup widget — A transient RenderWidget such as a dropdown that can be torn down while focus is still shifting.
Reentrant teardown — A notification (e.g. focus loss from Widget::Hide()) that fires in the middle of an object’s destruction.
Vulnerability window
- Reachability — A page causes a popup widget (e.g. dropdown) to open, creating an RWHVA registered as the window’s focus observer.
- Trigger — The popup is dismissed and the RWHVA is destroyed while its aura window_ still exists.
- Primitive — A focus-loss notification arrives reentrantly during destruction; FocusController dereferences the dangling observer pointer, a browser-process UAF.
- Escalation — Controlled reuse of the freed RWHVA memory could be shaped toward browser-process control-flow hijack (inferred).
Proof of concept
Conceptually, load a page with a element, open its popup to create the popup RWHVA, then dismiss it in a way that delivers a reentrant focus-loss (e.g. via Widget::Hide()) during the view’s destruction so the stale FocusChangeObserver is invoked on freed memory. No exploit code is provided.
Exploitation
- Spawn popup — Web content opens a /autofill popup, allocating a popup RWHVA that registers as focus observer (inferred).
- Race teardown — Dismiss the popup so the RWHVA is destroyed while window_ still lives and a focus change is pending (inferred).
- Reclaim memory — Groom the browser-process heap to place controlled data in the freed RWHVA slot (inferred).
- Hijack call — FocusController’s call through the dangling observer dispatches into attacker-controlled memory (inferred).
Detection & hunting
For defenders and detection engineers:
- grep for SetFocusChangeObserver / aura::client::GetFocusChangeObserver registrations lacking a matching clear on teardown — Enumerate classes that register as aura observers or window properties and verify each unregisters while the window is still valid during destruction.
- Crash signatures: UAF in FocusController focus-change dispatch pointing at RenderWidgetHostViewAura during shutdown — Hunt stability reports for reentrant focus-notification crashes in widget teardown paths.
Audit directions
- content/browser/renderer_host and ui/aura observer/property registrations — Audit all window-property observer pointers (focus, activation, capture) for symmetric register/unregister across every destruction path.
- Other RenderWidgetHostView platform subclasses — Check mac/views/ozone views for analogous observers that may not unsubscribe before the view is freed while the native window survives.