diff --git a/services/device/usb/mojo/device_impl.cc b/services/device/usb/mojo/device_impl.cc index 7f34bfb1a5222..468f7014b6845 100644 --- a/services/device/usb/mojo/device_impl.cc +++ b/services/device/usb/mojo/device_impl.cc @@ -407,6 +407,26 @@ void DeviceImpl::SetInterfaceAlternateSetting( return; } + // SET_INTERFACE is a control transfer addressed to an interface. Apply the + // same protected-class policy that ClaimInterface() and + // HasControlTransferPermission() enforce so that a compromised renderer + // cannot use this entry point to drive USBDEVFS_SETINTERFACE against a + // blocked interface class. + const mojom::UsbConfigurationInfo* config = device_->GetActiveConfiguration(); + if (config) { + auto interface_it = + std::ranges::find(config->interfaces, interface_number, + &mojom::UsbInterfaceInfo::interface_number); + if (interface_it != config->interfaces.end()) { + for (const auto& alternate : (*interface_it)->alternates) { + if (blocked_interface_classes_.contains(alternate->class_code)) { + std::move(callback).Run(false); + return; + } + } + } + } + device_handle_->SetInterfaceAlternateSetting( interface_number, alternate_setting, std::move(callback)); } diff --git a/services/device/usb/usb_device_handle_usbfs.cc b/services/device/usb/usb_device_handle_usbfs.cc index 1ce133cec5d59..6565c778b583e 100644 --- a/services/device/usb/usb_device_handle_usbfs.cc +++ b/services/device/usb/usb_device_handle_usbfs.cc @@ -689,6 +689,16 @@ void UsbDeviceHandleUsbfs::SetInterfaceAlternateSetting( return; } + // Match the macOS and Windows backends: do not forward SET_INTERFACE for an + // interface that has not been claimed. Without this, the kernel auto-claims + // the interface for our fd (drivers/usb/core/devio.c::checkintf()). + if (!IsInterfaceClaimedByThis(interface_number)) { + USB_LOG(DEBUG) << "Interface " << interface_number << " was not claimed."; + task_runner_->PostTask(FROM_HERE, + base::BindOnce(std::move(callback), false)); + return; + } + // USBDEVFS_SETINTERFACE is synchronous because it issues a SET_INTERFACE // request to the device so it must be performed on a thread where it is okay // to block.