diff --git a/services/device/usb/usb_device_handle_impl.cc b/services/device/usb/usb_device_handle_impl.cc index d4d31ffe42880..2e4f109cdb7bc 100644 --- a/services/device/usb/usb_device_handle_impl.cc +++ b/services/device/usb/usb_device_handle_impl.cc @@ -568,7 +568,16 @@ void UsbDeviceHandleImpl::SetConfiguration(int configuration_value, for (Transfer* transfer : transfers_) { transfer->Cancel(); } - claimed_interfaces_.clear(); + // Security: InterfaceClaimer's destructor calls libusb_release_interface(), + // which is a blocking call that must run on |blocking_task_runner_| (where + // the SEQUENCE_CHECKER was bound at construction in ClaimInterfaceBlocking). + // A synchronous clear() here drops the last ref on the UI thread, causing + // the destructor to race darwin_set_interface_altsetting on the same + // libusb darwin_interface struct. Mirror what Close() does at lines 547-549. + for (auto& map_entry : claimed_interfaces_) { + blocking_task_runner_->ReleaseSoon(FROM_HERE, std::move(map_entry.second)); + } + claimed_interfaces_.clear(); // Map now contains only nullptrs; safe to clear. blocking_task_runner_->PostTask( FROM_HERE,