693bdacc0e27188b423c57fd987d7ce8d018f8aa Add null check to prevent UAF during shutdown
The bug at a glance
A use-after-free reachable re-entrantly during RenderWidgetHostViewAura teardown: as rwhva_ is destroyed, selection_controller_ is freed, but the unwind re-enters TouchSelectionControllerClientAura::InvalidateClient, which called GetTouchSelectionController()->HideAndDisallowShowingAutomatically() on the freed/absent controller. It is a browser-process UAF, but it occurs only during shutdown of the view, is not obviously attacker-timed or heap-groomable from a web page, and the fix is a defensive null check — so impact is primarily a crash with limited exploitability rather than reliable control.
During RenderWidgetHostViewAura destruction, the touch-selection controller is torn down, yet a re-entrant path (child-frame touch-selection client destructor -> InvalidateClient) calls back into the now-freed selection controller.
Root cause
RenderWidgetHostViewAura::~RenderWidgetHostViewAura frees selection_controller_. Its destruction chain reaches ~TouchSelectionControllerClientAura -> ~TouchSelectionControllerClientChildFrame -> TouchSelectionControllerClientAura::InvalidateClient. InvalidateClient, when client == active_client_, called GetTouchSelectionController()->HideAndDisallowShowingAutomatically(). At that point the controller has already been freed/cleared, so the dereference is a use-after-free (or null deref). The fix wraps the call in ‘if (GetTouchSelectionController())’ so it is skipped when the controller is gone, while still resetting active_client_/active_menu_client_.
Key code
Null-guarding the touch-selection controller before use during re-entrant teardown.
if (client == active_client_) {
- GetTouchSelectionController()->HideAndDisallowShowingAutomatically();
+ if (GetTouchSelectionController()) {
+ GetTouchSelectionController()->HideAndDisallowShowingAutomatically();
+ }
active_client_ = &internal_client_;
active_menu_client_ = this;
}
Patch walkthrough
content/browser/renderer_host/input/touch_selection_controller_client_aura.cc— In InvalidateClient(), guards the HideAndDisallowShowingAutomatically() call with an explicit GetTouchSelectionController() null check so that when the controller has already been freed during RenderWidgetHostViewAura destruction the freed-object call is avoided; active_client_ and active_menu_client_ are still reset. The CHECK(client != &internal_client_, NotFatalUntil::M152) above is unchanged.
Background
RenderWidgetHostViewAura (rwhva_) — The Aura (desktop) view for a render widget in the browser process; owns the touch selection controller and clients.
TouchSelectionController — Manages the on-screen text-selection handles/quick menu; HideAndDisallowShowingAutomatically() hides handles. GetTouchSelectionController() returns the (possibly already-destroyed) controller instance.
Re-entrant teardown — Destructor chains that call virtual/client callbacks can re-enter sibling objects after a dependency has been freed, producing use-after-free during shutdown.
NotFatalUntil::M152 — A CHECK scheduled to become fatal in M152; indicates the invariant (client != internal_client_) is being hardened in the same area.
Vulnerability window
- Latent bug — InvalidateClient unconditionally dereferenced GetTouchSelectionController(), unsafe when reached during controller/view destruction. (inferred)
- Discovery — Tracked as Bug 542565481; a crash stack (HideHandles <- HideAndDisallowShowingAutomatically <- InvalidateClient <- ~ClientChildFrame <- ~ClientAura <- ~RenderWidgetHostViewAura) showed the freed-object call.
- Fix — 2026-09-02: null check added around the controller call (this commit).
Proof of concept
Conceptual only. The crash arises during RenderWidgetHostViewAura shutdown with an active touch-selection client in a child frame; reproducing requires destroying a view while touch selection is active (e.g. navigating/closing a frame that owns an active text selection). The diff shows no deterministic trigger and the UAF is a teardown-order race, so no working exploit is provided.
Exploitation
- Setup — Page establishes an active touch text selection in an out-of-process/child frame so a TouchSelectionControllerClientChildFrame is the active client. (inferred)
- Trigger — The RenderWidgetHostViewAura is destroyed (frame/tab teardown), whose destructor frees selection_controller_ and re-enters InvalidateClient. (inferred)
- Use-after-free — InvalidateClient dereferences the already-freed controller via HideAndDisallowShowingAutomatically(); exploitation would require winning the teardown race and grooming the freed allocation, which is difficult. (inferred)
Detection & hunting
For defenders and detection engineers:
- Crash stack through InvalidateClient during ~RenderWidgetHostViewAura — Watch for ASAN heap-use-after-free or null-deref with the HideHandles/HideAndDisallowShowingAutomatically/InvalidateClient/~TouchSelectionControllerClient* frames noted in the commit message.
- Shutdown crashes with active touch selection — Correlate crashes to sessions where touch text selection was active in a child frame at view teardown.
Audit directions
- TouchSelectionControllerClientAura / ChildFrame — Audit all GetTouchSelectionController() dereferences for teardown-time nullability; verify destructor ordering between RenderWidgetHostViewAura, selection_controller_, and client objects.
- Re-entrant destructor callbacks — Search for client/observer callbacks invoked from destructors that touch sibling objects which may already be freed; add liveness/null checks.