4e5229cb51160fe5d77b020d3d6e4366f50d7f46 [M152] Prevent UAF during re-entrant destruction in IME callouts.
The bug at a glance
A genuine use-after-free in the browser process: IME callouts can re-entrantly destroy the RenderWidgetHostViewAura / updated_view and free the TextInputState that the function keeps using after the callout returns. It is a cherry-pick to the M152 security branch (Bug 559510415,553133215) with weak-pointer guards added, consistent with a security-serviced UAF.
An attacker who can influence focus/IME state (e.g. via a renderer-driven text input update) can cause an IME callout such as SetVirtualKeyboardVisibilityIfEnabled or NotifySelectionBoundsChanged to re-entrantly destroy the view and free its text input state, leaving the browser process dereferencing a dangling ’this’, ‘updated_view’, or ‘state’ pointer – a browser-process UAF, the most valuable sandbox-escape surface.
Root cause
In RenderWidgetHostViewAura::OnUpdateTextInputStateCalled, several IME callouts (OnTextInputTypeChanged, SetVirtualKeyboardVisibilityIfEnabled true/false, UpdateTextInputState, NotifySelectionBoundsChanged) can pump messages and re-entrantly destroy the view or unregister updated_view, freeing the TextInputState* ‘state’. The original code only checked weak_this after a couple of callouts and never re-fetched ‘state’, so later code dereferenced a freed state object or a destroyed updated_view. The patch adds a check_alive() lambda validating weak_this, a new weak pointer to updated_view, text_input_manager_ liveness, and IsRegistered(updated_view) after each callout, and re-fetches state = text_input_manager_->GetTextInputState() after each callout so stale/freed state is never used.
Key code
Weak-pointer liveness check and state re-fetch after each IME callout
+ auto check_alive = [&]() -> bool {
+ if (!weak_this || !weak_updated_view || !text_input_manager_ ||
+ !text_input_manager_->IsRegistered(updated_view)) {
+ return false;
+ }
+ return true;
+ };
...
+ // ... freeing the object `state` points to.
+ state = text_input_manager_->GetTextInputState();
Patch walkthrough
content/browser/renderer_host/render_widget_host_view_aura.cc— Adds a weak pointer to updated_view and a check_alive() lambda (weak_this, weak_updated_view, text_input_manager_ registration) invoked after every IME callout, and re-fetches ‘state’ from the TextInputManager after each callout so a view/state freed re-entrantly during the callout is never dereferenced – directly closing the use-after-free.content/browser/renderer_host/render_widget_host_view_aura_unittest.cc— Adds a MockInputMethod override and a regression test (DestroyDuringSetVirtualKeyboardVisibilityIfEnabled) that synchronously destroys the view inside SetVirtualKeyboardVisibilityIfEnabled to exercise the re-entrant-destruction path the fix guards.
Background
RenderWidgetHostViewAura (RWHVA) — The Aura-platform browser-process view hosting a renderer widget and bridging to the OS InputMethod/IME.
IME callout — A call into the platform input method (OnTextInputTypeChanged, SetVirtualKeyboardVisibilityIfEnabled, NotifySelectionBoundsChanged) that can run nested message loops and re-enter browser code.
TextInputManager / TextInputState — Browser-side owner of per-view text input state; the ‘state’ pointer can be invalidated when a view is unregistered/destroyed.
WeakPtr liveness check — base::WeakPtr becomes null when the pointee is destroyed, letting re-entrancy-prone code detect that ’this’ or a tracked object was freed.
Vulnerability window
- Reachability — A text input state update (influenced by renderer-side focus/IME changes) invokes OnUpdateTextInputStateCalled, which issues IME callouts.
- Trigger — An IME callout (e.g. SetVirtualKeyboardVisibilityIfEnabled) pumps messages and re-entrantly destroys the RWHVA/updated_view, freeing TextInputState.
- Primitive — On unwind the function dereferences the dangling ’this’/‘updated_view’/‘state’, producing a browser-process use-after-free read/write (inferred exploit value).
- Escalation — A controlled UAF in the browser process is a classic sandbox-escape primitive if the freed allocation can be reclaimed with attacker-controlled data (inferred).
Proof of concept
Conceptually, drive the view into a focused text-input state so OnUpdateTextInputStateCalled reaches the virtual-keyboard branch, then arrange for the IME callout (SetVirtualKeyboardVisibilityIfEnabled / NotifySelectionBoundsChanged) to run a nested loop that destroys the view (the unit test models this by destroying view_ inside the callout). Pre-patch the subsequent dereference of ‘state’/‘updated_view’ hits freed memory. No exploit code is provided.
Exploitation
- Grooming — Attacker arranges heap state so the freed TextInputState/view allocation can be reclaimed with controlled bytes (inferred).
- Trigger — Induce re-entrant view destruction inside an IME callout during a text-input-state update (inferred).
- Use — Post-callout code reads/writes through the dangling ‘state’ or ‘updated_view’, corrupting browser-process memory (inferred).
Detection & hunting
For defenders and detection engineers:
- grep for IME/callout sites holding raw TextInputState/view pointers across SetVirtualKeyboardVisibilityIfEnabled/NotifySelectionBoundsChanged without a WeakPtr re-check* — Hunt browser-process code that calls into platform input methods and then dereferences pre-callout pointers; require weak-pointer validation and state re-fetch after each callout.
Audit directions
- Other RWHVA / RenderWidgetHostViewBase IME and focus paths, and other platform views (Win TSF, ChromeOS keyboard controller) — Look for functions that invoke message-pumping IME callouts and then use cached ’this’/view/state pointers without re-validating liveness.