91fd9726d351a8cf13d81a208c349cec3f99274a [M152] Prevent crash if WidgetBase is destroyed during GetTextInputType.
The bug at a glance
Use-after-free in the renderer’s WidgetBase during IME/text-input state updates. GetTextInputType() can synchronously run embedder/JS-observable logic (editing, focus, composition) that destroys the WidgetBase; the surrounding code then continues to touch this/weak_ptr_factory_ and member state, operating on a freed object. Renderer-process UAF reachable through normal text-input/composition flows is a classic high-severity memory-corruption primitive; the fix was cherry-picked to a stable branch (M152), consistent with high priority. Not critical because it requires specific re-entrant destruction timing during IME updates rather than trivially remote one-shot triggering.
During UpdateTextInputState and composition-range updates, calling GetTextInputType() can re-enter code that destroys the owning WidgetBase. The original code used the return value and continued accessing the object with no liveness check, so after destruction the method kept running on freed memory.
Root cause
GetTextInputType() dispatches to the client/frame widget, which during focus/editing/composition changes can tear down the WidgetBase synchronously. The patch snapshots a base::WeakPtr immediately before each GetTextInputType() call and returns early if the weak pointer is invalidated afterward, preventing continued use of the freed widget. The result is also cached in a local (text_input_type) so GetTextInputType is not called twice.
Key code
WeakPtr liveness checks inserted immediately after each GetTextInputType() call to bail out if the widget was destroyed.
base::WeakPtr<WidgetBase> weak_this = weak_ptr_factory_.GetWeakPtr();
ui::TextInputType new_type = GetTextInputType();
if (!weak_this) {
return;
}
...
base::WeakPtr<WidgetBase> weak_this = weak_ptr_factory_.GetWeakPtr();
ui::TextInputType text_input_type = GetTextInputType();
if (!weak_this) {
return;
}
if (text_input_type == ui::TextInputType::TEXT_INPUT_TYPE_NONE) { ... }
Patch walkthrough
third_party/blink/renderer/platform/widget/widget_base.cc— In UpdateTextInputState: takes a WeakPtr before GetTextInputType() and returns if it is cleared afterward. The existing WeakPtr previously declared inside the frame_widget block is removed since the guard now covers the earlier call site. In the composition-update path (~line 1457): takes a WeakPtr, calls GetTextInputType() once into a cached local text_input_type, returns if the widget was destroyed, then uses the cached value; the redundant inner WeakPtr in the else branch (around GetCompositionRange) is cleaned up.third_party/blink/renderer/platform/widget/input/widget_base_input_handler_unittest.cc— Adds a mock override for GetTextInputType and a regression test UpdateTextInputStateDestroysWidget that makes GetTextInputType() shut down and reset the widget_base_, verifying UpdateTextInputState no longer crashes (previously a UAF).
Background
WidgetBase — Blink/renderer-side object backing a RenderWidget; owns IME/text-input plumbing and can be destroyed as a side effect of focus/editing changes.
GetTextInputType() — Client/frame-widget call returning the current input type; it can synchronously trigger logic (focus/composition handling) that destroys the WidgetBase.
base::WeakPtr liveness check — A standard Chromium pattern: capture a WeakPtr before a potentially re-entrant call and test it afterward to detect self-destruction before continuing.
IME / composition update — Input-method text composition flows (UpdateTextInputState, composition range) that are driven by user/page editing activity and run this code path.
Vulnerability window
- pre-fix — GetTextInputType() could destroy the WidgetBase mid-method; subsequent access to this/members was a use-after-free. (inferred mechanism from commit message and test)
- fix (main) — refs/heads/main@{#1687328}: WeakPtr checks added after each GetTextInputType() call plus a regression unit test.
- merge (M152) — Cherry-picked to branch 7977 (M152) as 91fd9726d3, Bug 553827454, indicating stable-release-worthy severity.
Proof of concept
No PoC is derivable from the diff. The regression test drives the condition by having a mocked GetTextInputType destroy the widget, but a real-world trigger would require crafting page content/IME interaction that causes GetTextInputType to synchronously tear down the WidgetBase, which is not shown. Conceptually: an editable field whose focus/composition handling, invoked via GetTextInputType, destroys the widget during an IME state update.
Exploitation
- trigger — Cause an IME/text-input state update (focus change, composition) where GetTextInputType() re-enters code that destroys the WidgetBase. (inferred)
- free — WidgetBase is destroyed synchronously inside the GetTextInputType() call. (inferred)
- use — The method resumes and reads/writes the freed WidgetBase (weak_ptr_factory_, members, virtual dispatch), the UAF primitive. (inferred)
- escalation — Classic renderer UAF: reclaiming the freed allocation with controlled data could yield type confusion / control-flow influence; not demonstrated. (inferred)
Detection & hunting
For defenders and detection engineers:
- Renderer crash during IME/text-input —
- Fuzzing —
Audit directions
- WidgetBase re-entrancy —
- Analogous widget/IME code —