38c49d2a96defae98e7efcf2a2d06c8b17e5c77d [M144] Prevent use-after-free in WidgetBase::UpdateSurfaceAndScreen.
The bug at a glance
The subject and diff explicitly describe a use-after-free: client_->OrientationChanged() (and client_->UpdateLifecycle()) can synchronously destroy the WidgetBase, after which the function keeps dereferencing client_ and member state, giving a renderer-reachable UAF.
An attacker controlling page content can arrange for an orientation/lifecycle callback to tear down the owning widget while WidgetBase::UpdateSurfaceAndScreen is still mid-execution, turning a re-entrant destroy into a dangling-this use-after-free in the renderer.
Root cause
UpdateSurfaceAndScreen and the lifecycle helper call out to client_ methods (OrientationChanged, UpdateLifecycle) that can run script/observers which synchronously destroy the WidgetBase. On return the original stack frame continued to touch client_ and member fields through a now-freed ’this’. The fix captures a WeakPtr to ’this’ before each re-entrant client call and returns early if the weak pointer is invalidated, aborting further use of the freed object.
Key code
Weak-pointer guard after a re-entrant client callback that can free WidgetBase
if (orientation_changed) {
auto weak_this = weak_ptr_factory_.GetWeakPtr();
client_->OrientationChanged();
if (!weak_this) {
return;
}
}
Patch walkthrough
third_party/blink/renderer/platform/widget/widget_base.cc— Adds a weak_ptr_factory_.GetWeakPtr() snapshot before client_->UpdateLifecycle() and client_->OrientationChanged(), with an early return if the WidgetBase was destroyed during the call; this prevents the subsequent SetSuppressFrameRequestsWorkaroundFor704763Only() and DidUpdateSurfaceAndScreen() calls from dereferencing freed memory.
Background
WidgetBase — Blink platform object backing a renderer widget that owns surface/screen state and forwards lifecycle events to a client interface.
WeakPtr guard — Common Chromium idiom of capturing a WeakPtr before a re-entrant callback and bailing out if ’this’ was destroyed during it.
Re-entrant destruction — A callback into client code (orientation/lifecycle) can synchronously delete the caller object, invalidating the current ’this'.
Vulnerability window
- Reachability — Renderer reaches UpdateSurfaceAndScreen via a screen-info/orientation update during compositing (inferred).
- Trigger — client_->OrientationChanged() runs observers/script that destroy the owning WidgetBase (inferred).
- Primitive — Execution returns to the freed WidgetBase frame and dereferences client_/members, a use-after-free.
- Escalation — Controlled reclamation of the freed allocation could turn the UAF into memory corruption in the renderer (inferred).
Proof of concept
Conceptually, a page would register orientation-change / lifecycle handling that causes the widget’s host (e.g. a frame or plugin) to be detached and destroyed synchronously during the orientation callback, then rely on the post-callback code path still executing against the freed WidgetBase. No exploit code is provided.
Exploitation
- Setup — Construct a document/frame whose orientation or lifecycle callback can trigger widget teardown (inferred).
- Trigger — Cause a surface/screen update so OrientationChanged() fires and destroys the WidgetBase mid-function (inferred).
- Groom — Reallocate the freed WidgetBase storage with attacker-influenced data before the dangling dereference (inferred).
- Corrupt — Leverage the dangling client_/member access for a controlled read/write primitive in the renderer (inferred).
Detection & hunting
For defenders and detection engineers:
- weggli: ‘_->$call(); $obj->$next’ patterns where a client callback is followed by further member use without a weak-ptr check — Grep for calls to client_ methods in widget_base.cc and sibling widget code that are not immediately followed by a weak_this validity check.
- grep ‘GetWeakPtr’ vs re-entrant ‘client_->’ calls — Audit each client_-> callback that can run script/observers to confirm a WeakPtr guard exists before later member dereferences.
Audit directions
- third_party/blink/renderer/platform/widget/* — Review other WidgetBase methods that call into client_ (lifecycle, visual properties, focus) for missing weak-this checks after re-entrant callbacks.
- Blink callers of client interfaces that can destroy the caller — Look for any method pattern ‘callback(); then use member/this’ where callback can synchronously delete the object.