← All issues

[15] [WebKit] Pin WebPageProxy across completion handlers via RefPtr promotion

Severity: High | Component: WebKit UIProcess | 1682be9

Rated High because the diff promotes captured WeakPtr<WebPageProxy>/WeakPtr<WebProcessProxy> to RefPtr in multiple WebPageProxy completion handlers; the pre-fix shape if (!weakThis) return; weakThis->send(...); is not atomic on the main run loop and the object can be destroyed between the null check and the dereference.

Across loadSimulatedRequest, loadAlternateHTML, reload, executeEditCommand, contextMenuItemSelected, didPerformDictionaryLookup, and scheduleSetObscuredContentInsetsDispatch, WeakPtr captures are promoted to RefPtr once at the top of the lambda and used for the rest of the call.

Source/WebKit/UIProcess/WebPageProxy.cpp

- [weakThis = WeakPtr { *this }](auto result) {
- if (!weakThis) return;
- weakThis->send(Messages::...);
+ [weakThis = WeakPtr { *this }](auto result) {
+ RefPtr protectedThis = weakThis.get();
+ if (!protectedThis) return;
+ protectedThis->send(Messages::...);

WeakPtr promoted-too-late: the null check tested liveness, but the subsequent method call could run after destruction because no reference was held across the gap.

Each lambda promotes its weak capture to RefPtr (or Ref) before any method call. loadSimulatedRequest is the most egregious case — it had no null check at all and dereferenced weakProcess directly. The other call sites had the if (!weakThis) return; shape that is correct for liveness but does not pin the pointee for subsequent calls.

WeakPtr::operator bool reports current liveness; it does not extend lifetime. Completion handlers in WebPageProxy are dispatched on the main run loop (callOnMainRunLoop) or fired after asynchronous sandbox-extension processing. Between the null check and the final dereference, an unrelated owner can drop its last Ref to the WebPageProxy / WebProcessProxy.

Two pre-fix subpatterns:

(1)  weakProcess->send(...);                 // no null check, direct UAF
(2)  if (!weakThis) return;                  // liveness window
     ...                                     // unrelated work
     weakThis->send(...);                    // dangling here
🔒

The lifetime and ownership implications of UI-process completion handlers, and what destruction-race scenarios remain reachable, are examined in depth.

Subscribe to read more

🔒

Multiple reusable audit patterns identified for finding more instances of this bug class across the UIProcess tree, with concrete grep targets.

Subscribe to read more