diff options
Diffstat (limited to 'chromium/services/device/usb')
8 files changed, 104 insertions, 34 deletions
diff --git a/chromium/services/device/usb/mojo/device_manager_impl.cc b/chromium/services/device/usb/mojo/device_manager_impl.cc index 2c7b79af77c..8c3aa4ee25b 100644 --- a/chromium/services/device/usb/mojo/device_manager_impl.cc +++ b/chromium/services/device/usb/mojo/device_manager_impl.cc @@ -123,6 +123,7 @@ void DeviceManagerImpl::CheckAccess(const std::string& guid, void DeviceManagerImpl::OpenFileDescriptor( const std::string& guid, + uint32_t drop_privileges_mask, OpenFileDescriptorCallback callback) { scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid); if (!device) { @@ -133,8 +134,8 @@ void DeviceManagerImpl::OpenFileDescriptor( base::AdaptCallbackForRepeating(std::move(callback)); auto devpath = static_cast<device::UsbDeviceLinux*>(device.get())->device_path(); - chromeos::PermissionBrokerClient::Get()->OpenPath( - devpath, + chromeos::PermissionBrokerClient::Get()->OpenPathWithDroppedPrivileges( + devpath, drop_privileges_mask, base::BindOnce(&DeviceManagerImpl::OnOpenFileDescriptor, weak_factory_.GetWeakPtr(), copyable_callback), base::BindOnce(&DeviceManagerImpl::OnOpenFileDescriptorError, diff --git a/chromium/services/device/usb/mojo/device_manager_impl.h b/chromium/services/device/usb/mojo/device_manager_impl.h index 5684eab03cf..a048b379dff 100644 --- a/chromium/services/device/usb/mojo/device_manager_impl.h +++ b/chromium/services/device/usb/mojo/device_manager_impl.h @@ -70,6 +70,7 @@ class DeviceManagerImpl : public mojom::UsbDeviceManager, CheckAccessCallback callback) override; void OpenFileDescriptor(const std::string& guid, + uint32_t drop_privileges_mask, OpenFileDescriptorCallback callback) override; void OnOpenFileDescriptor(OpenFileDescriptorCallback callback, diff --git a/chromium/services/device/usb/usb_device_handle_usbfs.cc b/chromium/services/device/usb/usb_device_handle_usbfs.cc index 90e2be66708..68eb5658725 100644 --- a/chromium/services/device/usb/usb_device_handle_usbfs.cc +++ b/chromium/services/device/usb/usb_device_handle_usbfs.cc @@ -17,6 +17,7 @@ #include "base/files/file_descriptor_watcher_posix.h" #include "base/logging.h" #include "base/memory/ref_counted_memory.h" +#include "base/numerics/checked_math.h" #include "base/posix/eintr_wrapper.h" #include "base/sequence_checker.h" #include "base/stl_util.h" @@ -169,7 +170,7 @@ class UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper { DISALLOW_COPY_AND_ASSIGN(BlockingTaskRunnerHelper); }; -struct UsbDeviceHandleUsbfs::Transfer { +struct UsbDeviceHandleUsbfs::Transfer final { Transfer() = delete; Transfer(scoped_refptr<base::RefCountedBytes> buffer, TransferCallback callback); @@ -291,8 +292,12 @@ void UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::SetInterface( USB_PLOG(DEBUG) << "Failed to set interface " << interface_number << " to alternate setting " << alternate_setting; } - task_runner_->PostTask(FROM_HERE, - base::BindOnce(std::move(callback), rc == 0)); + task_runner_->PostTask( + FROM_HERE, + base::BindOnce( + &UsbDeviceHandleUsbfs::SetAlternateInterfaceSettingComplete, + device_handle_, interface_number, alternate_setting, rc == 0, + std::move(callback))); } void UsbDeviceHandleUsbfs::BlockingTaskRunnerHelper::ResetDevice( @@ -386,9 +391,9 @@ UsbDeviceHandleUsbfs::Transfer::Transfer( scoped_refptr<base::RefCountedBytes> buffer, IsochronousTransferCallback callback) : buffer(buffer), isoc_callback(std::move(callback)) { - memset( - &urb, 0, - sizeof(urb) + sizeof(usbdevfs_iso_packet_desc) * urb.number_of_packets); + // This buffer size calculation is checked in operator new(). + memset(&urb, 0, + sizeof(urb) + sizeof(urb.iso_frame_desc[0]) * urb.number_of_packets); urb.usercontext = this; urb.buffer = buffer->front(); } @@ -396,10 +401,15 @@ UsbDeviceHandleUsbfs::Transfer::Transfer( UsbDeviceHandleUsbfs::Transfer::~Transfer() = default; void* UsbDeviceHandleUsbfs::Transfer::operator new( - std::size_t size, + size_t size, size_t number_of_iso_packets) { - void* p = ::operator new(size + sizeof(usbdevfs_iso_packet_desc) * - number_of_iso_packets); + // The checked math should pass as long as Mojo message size limits are being + // enforced. + size_t total_size = + base::CheckAdd(size, base::CheckMul(sizeof(urb.iso_frame_desc[0]), + number_of_iso_packets)) + .ValueOrDie(); + void* p = ::operator new(total_size); Transfer* transfer = static_cast<Transfer*>(p); transfer->urb.number_of_packets = number_of_iso_packets; return p; @@ -763,6 +773,19 @@ void UsbDeviceHandleUsbfs::SetConfigurationComplete(int configuration_value, std::move(callback).Run(success); } +void UsbDeviceHandleUsbfs::SetAlternateInterfaceSettingComplete( + int interface_number, + int alternate_setting, + bool success, + ResultCallback callback) { + DCHECK(sequence_checker_.CalledOnValidSequence()); + if (success && device_) { + interfaces_[interface_number].alternate_setting = alternate_setting; + RefreshEndpointInfo(); + } + std::move(callback).Run(success); +} + void UsbDeviceHandleUsbfs::ReleaseInterfaceComplete(int interface_number, ResultCallback callback) { DCHECK(sequence_checker_.CalledOnValidSequence()); diff --git a/chromium/services/device/usb/usb_device_handle_usbfs.h b/chromium/services/device/usb/usb_device_handle_usbfs.h index 33a09d00542..949ddd05327 100644 --- a/chromium/services/device/usb/usb_device_handle_usbfs.h +++ b/chromium/services/device/usb/usb_device_handle_usbfs.h @@ -103,6 +103,10 @@ class UsbDeviceHandleUsbfs : public UsbDeviceHandle { void SetConfigurationComplete(int configuration_value, bool success, ResultCallback callback); + void SetAlternateInterfaceSettingComplete(int interface_number, + int alternate_setting, + bool success, + ResultCallback callback); void ReleaseInterfaceComplete(int interface_number, ResultCallback callback); void IsochronousTransferInternal(uint8_t endpoint_address, scoped_refptr<base::RefCountedBytes> buffer, diff --git a/chromium/services/device/usb/usb_device_handle_win.cc b/chromium/services/device/usb/usb_device_handle_win.cc index 2cac1b0cc6d..e9364245b16 100644 --- a/chromium/services/device/usb/usb_device_handle_win.cc +++ b/chromium/services/device/usb/usb_device_handle_win.cc @@ -26,6 +26,7 @@ #include "base/stl_util.h" #include "base/strings/string16.h" #include "base/task/post_task.h" +#include "base/task/thread_pool.h" #include "base/threading/scoped_blocking_call.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/win/object_watcher.h" @@ -335,8 +336,8 @@ void UsbDeviceHandleWin::SetInterfaceAlternateSetting(int interface_number, // Use a strong reference to |this| rather than a weak pointer to prevent // |interface.handle| from being freed because |this| was destroyed. - base::PostTaskAndReplyWithResult( - FROM_HERE, {base::ThreadPool(), base::MayBlock()}, + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, base::BindOnce(&SetCurrentAlternateSettingBlocking, interface.handle.Get(), alternate_setting), base::BindOnce(&UsbDeviceHandleWin::OnSetAlternateInterfaceSetting, this, @@ -388,8 +389,8 @@ void UsbDeviceHandleWin::ClearHalt(mojom::UsbTransferDirection direction, // Use a strong reference to |this| rather than a weak pointer to prevent // |interface.handle| from being freed because |this| was destroyed. - base::PostTaskAndReplyWithResult( - FROM_HERE, {base::ThreadPool(), base::MayBlock()}, + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, base::BindOnce(&ResetPipeBlocking, interface.handle.Get(), endpoint_address), base::BindOnce(&UsbDeviceHandleWin::OnClearHalt, this, @@ -1017,13 +1018,22 @@ void UsbDeviceHandleWin::GotDescriptorFromNodeConnection( if (win32_result != ERROR_SUCCESS) { SetLastError(win32_result); USB_PLOG(ERROR) << "Failed to read descriptor from node connection"; - std::move(callback).Run(UsbTransferStatus::TRANSFER_ERROR, nullptr, 0); + std::move(callback).Run(UsbTransferStatus::TRANSFER_ERROR, + /*buffer=*/nullptr, /*length=*/0); + return; + } + + if (bytes_transferred < sizeof(USB_DESCRIPTOR_REQUEST)) { + USB_LOG(ERROR) << "Descriptor response too short (" << bytes_transferred + << " < " << sizeof(USB_DESCRIPTOR_REQUEST) << ")"; + std::move(callback).Run(UsbTransferStatus::TRANSFER_ERROR, + /*buffer=*/nullptr, /*length=*/0); return; } - DCHECK_GE(bytes_transferred, sizeof(USB_DESCRIPTOR_REQUEST)); bytes_transferred -= sizeof(USB_DESCRIPTOR_REQUEST); - DCHECK_LE(bytes_transferred, original_buffer->size()); + bytes_transferred = std::min(bytes_transferred, original_buffer->size()); + memcpy(original_buffer->front(), request_buffer->front() + sizeof(USB_DESCRIPTOR_REQUEST), bytes_transferred); diff --git a/chromium/services/device/usb/usb_service.h b/chromium/services/device/usb/usb_service.h index 97a44f0ccea..3e9df5c05ab 100644 --- a/chromium/services/device/usb/usb_service.h +++ b/chromium/services/device/usb/usb_service.h @@ -12,7 +12,7 @@ #include <vector> #include "base/bind_helpers.h" -#include "base/logging.h" +#include "base/check.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/observer_list.h" diff --git a/chromium/services/device/usb/usb_service_linux.cc b/chromium/services/device/usb/usb_service_linux.cc index d5cef63fe30..7e7eb833b76 100644 --- a/chromium/services/device/usb/usb_service_linux.cc +++ b/chromium/services/device/usb/usb_service_linux.cc @@ -34,6 +34,8 @@ namespace device { namespace { +constexpr char kSubsystemUsb[] = "usb"; + // Standard USB requests and descriptor types: const uint16_t kUsbVersion2_1 = 0x0210; @@ -109,7 +111,8 @@ void UsbServiceLinux::BlockingTaskRunnerHelper::Start() { // Initializing udev for device enumeration and monitoring may fail. In that // case this service will continue to exist but no devices will be found. - watcher_ = UdevWatcher::StartWatching(this); + watcher_ = UdevWatcher::StartWatching( + this, {UdevWatcher::Filter(kSubsystemUsb, "")}); if (watcher_) watcher_->EnumerateExistingDevices(); @@ -123,9 +126,12 @@ void UsbServiceLinux::BlockingTaskRunnerHelper::OnDeviceAdded( base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::MAY_BLOCK); + +#if DCHECK_IS_ON() const char* subsystem = udev_device_get_subsystem(device.get()); - if (!subsystem || strcmp(subsystem, "usb") != 0) - return; + DCHECK(subsystem); + DCHECK_EQ(base::StringPiece(subsystem), kSubsystemUsb); +#endif const char* value = udev_device_get_devnode(device.get()); if (!value) diff --git a/chromium/services/device/usb/usb_service_win.cc b/chromium/services/device/usb/usb_service_win.cc index 6acaf445f91..4e8989f6d3d 100644 --- a/chromium/services/device/usb/usb_service_win.cc +++ b/chromium/services/device/usb/usb_service_win.cc @@ -24,8 +24,11 @@ #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/threading/scoped_blocking_call.h" +#include "base/threading/scoped_thread_priority.h" #include "base/threading/thread_task_runner_handle.h" #include "base/win/registry.h" +#include "base/win/scoped_devinfo.h" #include "base/win/scoped_handle.h" #include "components/device_event_log/device_event_log.h" #include "services/device/usb/usb_descriptors.h" @@ -37,16 +40,13 @@ namespace device { namespace { -struct DevInfoScopedTraits { - static HDEVINFO InvalidValue() { return INVALID_HANDLE_VALUE; } - static void Free(HDEVINFO h) { SetupDiDestroyDeviceInfoList(h); } -}; - -using ScopedDevInfo = base::ScopedGeneric<HDEVINFO, DevInfoScopedTraits>; - base::Optional<uint32_t> GetDeviceUint32Property(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY& property) { + // SetupDiGetDeviceProperty() makes an RPC which may block. + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::MAY_BLOCK); + DEVPROPTYPE property_type; uint32_t buffer; if (!SetupDiGetDeviceProperty( @@ -63,6 +63,10 @@ base::Optional<base::string16> GetDeviceStringProperty( HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY& property) { + // SetupDiGetDeviceProperty() makes an RPC which may block. + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::MAY_BLOCK); + DEVPROPTYPE property_type; DWORD required_size; if (SetupDiGetDeviceProperty(dev_info, dev_info_data, &property, @@ -87,6 +91,10 @@ base::Optional<std::vector<base::string16>> GetDeviceStringListProperty( HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data, const DEVPROPKEY& property) { + // SetupDiGetDeviceProperty() makes an RPC which may block. + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::MAY_BLOCK); + DEVPROPTYPE property_type; DWORD required_size; if (SetupDiGetDeviceProperty(dev_info, dev_info_data, &property, @@ -236,7 +244,7 @@ bool GetDeviceInterfaceDetails(HDEVINFO dev_info, base::string16 GetDevicePath(const base::string16& instance_id, const GUID& device_interface_guid) { - ScopedDevInfo dev_info( + base::win::ScopedDevInfo dev_info( SetupDiGetClassDevs(&device_interface_guid, instance_id.c_str(), 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)); if (!dev_info.is_valid()) { @@ -287,7 +295,8 @@ int GetInterfaceNumber(const base::string16& instance_id) { UsbDeviceWin::FunctionInfo GetFunctionInfo(const base::string16& instance_id) { UsbDeviceWin::FunctionInfo info; - ScopedDevInfo dev_info(SetupDiCreateDeviceInfoList(nullptr, nullptr)); + base::win::ScopedDevInfo dev_info( + SetupDiCreateDeviceInfoList(nullptr, nullptr)); if (!dev_info.is_valid()) { USB_PLOG(ERROR) << "SetupDiCreateDeviceInfoList"; return info; @@ -310,6 +319,10 @@ UsbDeviceWin::FunctionInfo GetFunctionInfo(const base::string16& instance_id) { if (!base::EqualsCaseInsensitiveASCII(info.driver, L"winusb")) return info; + // Boost priority while potentially loading Advapi32.dll on a background + // thread for the registry functions used below. + SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY(); + // There is no standard device interface GUID for USB functions and so we // must discover the set of GUIDs that have been set in the registry by // the INF file or Microsoft OS Compatibility descriptors before @@ -332,6 +345,10 @@ UsbDeviceWin::FunctionInfo GetFunctionInfo(const base::string16& instance_id) { } for (const auto& guid_string : device_interface_guids) { + // Boost priority while potentially loading Ole32.dll on a background + // thread for CLSIDFromString(). + SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY(); + GUID guid; if (FAILED(CLSIDFromString(guid_string.c_str(), &guid))) { USB_LOG(ERROR) << "Failed to parse device interface GUID: " @@ -357,7 +374,11 @@ class UsbServiceWin::BlockingTaskRunnerHelper { ~BlockingTaskRunnerHelper() {} void EnumerateDevices() { - ScopedDevInfo dev_info( + // Boost priority while potentially loading SetupAPI.dll for the following + // functions on a background thread. + SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY(); + + base::win::ScopedDevInfo dev_info( SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, nullptr, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)); if (!dev_info.is_valid()) { @@ -384,7 +405,11 @@ class UsbServiceWin::BlockingTaskRunnerHelper { } void OnDeviceAdded(const GUID& guid, const base::string16& device_path) { - ScopedDevInfo dev_info(SetupDiGetClassDevs( + // Boost priority while potentially loading SetupAPI.dll and Ole32.dll on a + // background thread for the following functions. + SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY(); + + base::win::ScopedDevInfo dev_info(SetupDiGetClassDevs( &guid, nullptr, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)); if (!dev_info.is_valid()) { USB_PLOG(ERROR) << "Failed to set up device enumeration"; @@ -407,6 +432,7 @@ class UsbServiceWin::BlockingTaskRunnerHelper { } } + private: void EnumerateDevice(HDEVINFO dev_info, SP_DEVICE_INTERFACE_DATA* device_interface_data, const base::Optional<base::string16>& opt_device_path) { @@ -499,7 +525,6 @@ class UsbServiceWin::BlockingTaskRunnerHelper { std::move(parent_path), interface_number, info)); } - private: std::unordered_map<base::string16, base::string16> hub_paths_; // Calls back to |service_| must be posted to |service_task_runner_|, which |