1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "services/device/usb/usb_service_win.h"
6 
7 #include <objbase.h>
8 #include <setupapi.h>
9 #include <stdint.h>
10 #include <usbiodef.h>
11 
12 #define INITGUID
13 #include <devpkey.h>
14 
15 #include "base/bind.h"
16 #include "base/location.h"
17 #include "base/memory/free_deleter.h"
18 #include "base/memory/ptr_util.h"
19 #include "base/scoped_generic.h"
20 #include "base/single_thread_task_runner.h"
21 #include "base/stl_util.h"
22 #include "base/strings/string_split.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/sys_string_conversions.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "base/threading/thread_task_runner_handle.h"
27 #include "base/win/registry.h"
28 #include "base/win/scoped_handle.h"
29 #include "components/device_event_log/device_event_log.h"
30 #include "services/device/usb/usb_descriptors.h"
31 #include "services/device/usb/usb_device_handle.h"
32 #include "services/device/usb/webusb_descriptors.h"
33 
34 namespace device {
35 
36 namespace {
37 
38 struct DevInfoScopedTraits {
InvalidValuedevice::__anonefc0a5860111::DevInfoScopedTraits39   static HDEVINFO InvalidValue() { return INVALID_HANDLE_VALUE; }
Freedevice::__anonefc0a5860111::DevInfoScopedTraits40   static void Free(HDEVINFO h) { SetupDiDestroyDeviceInfoList(h); }
41 };
42 
43 using ScopedDevInfo = base::ScopedGeneric<HDEVINFO, DevInfoScopedTraits>;
44 
GetDeviceUint32Property(HDEVINFO dev_info,SP_DEVINFO_DATA * dev_info_data,const DEVPROPKEY & property,uint32_t * property_buffer)45 bool GetDeviceUint32Property(HDEVINFO dev_info,
46                              SP_DEVINFO_DATA* dev_info_data,
47                              const DEVPROPKEY& property,
48                              uint32_t* property_buffer) {
49   DEVPROPTYPE property_type;
50   if (!SetupDiGetDeviceProperty(dev_info, dev_info_data, &property,
51                                 &property_type,
52                                 reinterpret_cast<PBYTE>(property_buffer),
53                                 sizeof(*property_buffer), nullptr, 0) ||
54       property_type != DEVPROP_TYPE_UINT32) {
55     return false;
56   }
57 
58   return true;
59 }
60 
GetDeviceStringProperty(HDEVINFO dev_info,SP_DEVINFO_DATA * dev_info_data,const DEVPROPKEY & property,base::string16 * buffer)61 bool GetDeviceStringProperty(HDEVINFO dev_info,
62                              SP_DEVINFO_DATA* dev_info_data,
63                              const DEVPROPKEY& property,
64                              base::string16* buffer) {
65   DEVPROPTYPE property_type;
66   DWORD required_size;
67   if (SetupDiGetDeviceProperty(dev_info, dev_info_data, &property,
68                                &property_type, nullptr, 0, &required_size, 0) ||
69       GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
70       property_type != DEVPROP_TYPE_STRING) {
71     return false;
72   }
73 
74   if (!SetupDiGetDeviceProperty(
75           dev_info, dev_info_data, &property, &property_type,
76           reinterpret_cast<PBYTE>(base::WriteInto(buffer, required_size)),
77           required_size, nullptr, 0)) {
78     return false;
79   }
80 
81   return true;
82 }
83 
GetDeviceStringListProperty(HDEVINFO dev_info,SP_DEVINFO_DATA * dev_info_data,const DEVPROPKEY & property,std::vector<base::string16> * result)84 bool GetDeviceStringListProperty(HDEVINFO dev_info,
85                                  SP_DEVINFO_DATA* dev_info_data,
86                                  const DEVPROPKEY& property,
87                                  std::vector<base::string16>* result) {
88   DEVPROPTYPE property_type;
89   DWORD required_size;
90   if (SetupDiGetDeviceProperty(dev_info, dev_info_data, &property,
91                                &property_type, nullptr, 0, &required_size, 0) ||
92       GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
93       property_type != DEVPROP_TYPE_STRING_LIST) {
94     return false;
95   }
96 
97   base::string16 buffer;
98   if (!SetupDiGetDeviceProperty(
99           dev_info, dev_info_data, &property, &property_type,
100           reinterpret_cast<PBYTE>(base::WriteInto(&buffer, required_size)),
101           required_size, nullptr, 0)) {
102     return false;
103   }
104 
105   // Windows string list properties use a NUL character as the delimiter.
106   *result = base::SplitString(buffer, base::StringPiece16(L"\0", 1),
107                               base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
108   return true;
109 }
110 
GetServiceName(HDEVINFO dev_info,SP_DEVINFO_DATA * dev_info_data,base::string16 * service_name)111 bool GetServiceName(HDEVINFO dev_info,
112                     SP_DEVINFO_DATA* dev_info_data,
113                     base::string16* service_name) {
114   base::string16 buffer;
115   if (!GetDeviceStringProperty(dev_info, dev_info_data, DEVPKEY_Device_Service,
116                                &buffer)) {
117     return false;
118   }
119 
120   // Windows pads this string with a variable number of NUL bytes for no
121   // discernible reason.
122   *service_name = base::TrimString(buffer, base::StringPiece16(L"\0", 1),
123                                    base::TRIM_TRAILING)
124                       .as_string();
125   return true;
126 }
127 
GetDeviceInterfaceDetails(HDEVINFO dev_info,SP_DEVICE_INTERFACE_DATA * device_interface_data,base::string16 * device_path,uint32_t * bus_number,uint32_t * port_number,base::string16 * parent_instance_id,std::vector<base::string16> * child_instance_ids,base::string16 * service_name)128 bool GetDeviceInterfaceDetails(HDEVINFO dev_info,
129                                SP_DEVICE_INTERFACE_DATA* device_interface_data,
130                                base::string16* device_path,
131                                uint32_t* bus_number,
132                                uint32_t* port_number,
133                                base::string16* parent_instance_id,
134                                std::vector<base::string16>* child_instance_ids,
135                                base::string16* service_name) {
136   DWORD required_size = 0;
137   if (SetupDiGetDeviceInterfaceDetail(dev_info, device_interface_data, nullptr,
138                                       0, &required_size, nullptr) ||
139       GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
140     return false;
141   }
142 
143   std::unique_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA, base::FreeDeleter>
144   device_interface_detail_data(
145       static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(malloc(required_size)));
146   device_interface_detail_data->cbSize = sizeof(*device_interface_detail_data);
147 
148   SP_DEVINFO_DATA dev_info_data = {};
149   dev_info_data.cbSize = sizeof(dev_info_data);
150 
151   if (!SetupDiGetDeviceInterfaceDetail(
152           dev_info, device_interface_data, device_interface_detail_data.get(),
153           required_size, nullptr, &dev_info_data)) {
154     USB_PLOG(ERROR) << "SetupDiGetDeviceInterfaceDetail";
155     return false;
156   }
157 
158   if (device_path) {
159     *device_path = base::string16(device_interface_detail_data->DevicePath);
160   }
161 
162   if (bus_number) {
163     if (!GetDeviceUint32Property(dev_info, &dev_info_data,
164                                  DEVPKEY_Device_BusNumber, bus_number)) {
165       USB_PLOG(ERROR) << "Failed to get device bus number";
166       return false;
167     }
168   }
169 
170   if (port_number) {
171     if (!GetDeviceUint32Property(dev_info, &dev_info_data,
172                                  DEVPKEY_Device_Address, port_number)) {
173       USB_PLOG(ERROR) << "Failed to get device address";
174       return false;
175     }
176   }
177 
178   if (parent_instance_id) {
179     if (!GetDeviceStringProperty(dev_info, &dev_info_data,
180                                  DEVPKEY_Device_Parent, parent_instance_id)) {
181       USB_PLOG(ERROR) << "Failed to get the device parent";
182       return false;
183     }
184   }
185 
186   if (child_instance_ids) {
187     if (!GetDeviceStringListProperty(dev_info, &dev_info_data,
188                                      DEVPKEY_Device_Children,
189                                      child_instance_ids) &&
190         GetLastError() != ERROR_NOT_FOUND) {
191       USB_PLOG(ERROR) << "Failed to get device children";
192       return false;
193     }
194   }
195 
196   if (service_name) {
197     if (!GetServiceName(dev_info, &dev_info_data, service_name)) {
198       USB_PLOG(ERROR) << "Failed to get device driver name";
199       return false;
200     }
201   }
202 
203   return true;
204 }
205 
GetDevicePath(const base::string16 & instance_id,const GUID & device_interface_guid,base::string16 * device_path)206 bool GetDevicePath(const base::string16& instance_id,
207                    const GUID& device_interface_guid,
208                    base::string16* device_path) {
209   ScopedDevInfo dev_info(
210       SetupDiGetClassDevs(&device_interface_guid, instance_id.c_str(), 0,
211                           DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
212   if (!dev_info.is_valid()) {
213     USB_PLOG(ERROR) << "SetupDiGetClassDevs";
214     return false;
215   }
216 
217   SP_DEVICE_INTERFACE_DATA device_interface_data = {};
218   device_interface_data.cbSize = sizeof(device_interface_data);
219   if (!SetupDiEnumDeviceInterfaces(dev_info.get(), nullptr,
220                                    &device_interface_guid, 0,
221                                    &device_interface_data)) {
222     USB_PLOG(ERROR) << "SetupDiEnumDeviceInterfaces";
223     return false;
224   }
225 
226   return GetDeviceInterfaceDetails(dev_info.get(), &device_interface_data,
227                                    device_path, nullptr, nullptr, nullptr,
228                                    nullptr, nullptr);
229 }
230 
GetWinUsbDevicePath(const base::string16 & instance_id,base::string16 * device_path)231 bool GetWinUsbDevicePath(const base::string16& instance_id,
232                          base::string16* device_path) {
233   ScopedDevInfo dev_info(SetupDiCreateDeviceInfoList(nullptr, nullptr));
234   if (!dev_info.is_valid()) {
235     USB_PLOG(ERROR) << "SetupDiCreateDeviceInfoList";
236     return false;
237   }
238 
239   SP_DEVINFO_DATA dev_info_data = {};
240   dev_info_data.cbSize = sizeof(dev_info_data);
241   if (!SetupDiOpenDeviceInfo(dev_info.get(), instance_id.c_str(), nullptr, 0,
242                              &dev_info_data)) {
243     USB_PLOG(ERROR) << "SetupDiOpenDeviceInfo";
244     return false;
245   }
246 
247   base::string16 service_name;
248   if (!GetServiceName(dev_info.get(), &dev_info_data, &service_name)) {
249     USB_PLOG(ERROR) << "Could not get child device's service name";
250     return false;
251   }
252 
253   if (!base::EqualsCaseInsensitiveASCII(service_name, L"winusb"))
254     return false;
255 
256   // There is no standard device interface GUID for USB functions and so we
257   // must discover the set of GUIDs that have been set in the registry by
258   // the INF file or Microsoft OS Compatibility descriptors before
259   // SetupDiGetDeviceInterfaceDetail() can be used to get the device path.
260   HKEY key = SetupDiOpenDevRegKey(dev_info.get(), &dev_info_data,
261                                   DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
262   if (key == INVALID_HANDLE_VALUE) {
263     USB_PLOG(ERROR) << "Could not open device registry key";
264     return false;
265   }
266   base::win::RegKey scoped_key(key);
267 
268   std::vector<std::wstring> device_interface_guids;
269   LONG result =
270       scoped_key.ReadValues(L"DeviceInterfaceGUIDs", &device_interface_guids);
271   if (result != ERROR_SUCCESS) {
272     USB_LOG(ERROR) << "Could not read device interface GUIDs: "
273                    << logging::SystemErrorCodeToString(result);
274     return false;
275   }
276 
277   for (const auto& guid_string : device_interface_guids) {
278     GUID guid;
279     if (FAILED(CLSIDFromString(guid_string.c_str(), &guid))) {
280       USB_LOG(ERROR) << "Failed to parse device interface GUID: "
281                      << guid_string;
282       continue;
283     }
284 
285     if (GetDevicePath(instance_id, guid, device_path))
286       return true;
287   }
288 
289   return false;
290 }
291 
292 }  // namespace
293 
294 class UsbServiceWin::BlockingTaskRunnerHelper {
295  public:
BlockingTaskRunnerHelper(base::WeakPtr<UsbServiceWin> service)296   explicit BlockingTaskRunnerHelper(base::WeakPtr<UsbServiceWin> service)
297       : service_task_runner_(base::ThreadTaskRunnerHandle::Get()),
298         service_(service) {}
~BlockingTaskRunnerHelper()299   ~BlockingTaskRunnerHelper() {}
300 
EnumerateDevices()301   void EnumerateDevices() {
302     ScopedDevInfo dev_info(
303         SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, nullptr, 0,
304                             DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
305     if (!dev_info.is_valid()) {
306       USB_PLOG(ERROR) << "Failed to set up device enumeration";
307       service_task_runner_->PostTask(
308           FROM_HERE, base::BindOnce(&UsbServiceWin::HelperStarted, service_));
309       return;
310     }
311 
312     SP_DEVICE_INTERFACE_DATA device_interface_data = {};
313     device_interface_data.cbSize = sizeof(device_interface_data);
314     for (DWORD i = 0; SetupDiEnumDeviceInterfaces(dev_info.get(), nullptr,
315                                                   &GUID_DEVINTERFACE_USB_DEVICE,
316                                                   i, &device_interface_data);
317          ++i) {
318       EnumerateDevice(dev_info.get(), &device_interface_data, base::nullopt);
319     }
320 
321     if (GetLastError() != ERROR_NO_MORE_ITEMS)
322       USB_PLOG(ERROR) << "Failed to enumerate devices";
323 
324     service_task_runner_->PostTask(
325         FROM_HERE, base::BindOnce(&UsbServiceWin::HelperStarted, service_));
326   }
327 
EnumerateDevicePath(const base::string16 & device_path)328   void EnumerateDevicePath(const base::string16& device_path) {
329     ScopedDevInfo dev_info(
330         SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, nullptr, 0,
331                             DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
332     if (!dev_info.is_valid()) {
333       USB_PLOG(ERROR) << "Failed to set up device enumeration";
334       return;
335     }
336 
337     SP_DEVICE_INTERFACE_DATA device_interface_data = {};
338     device_interface_data.cbSize = sizeof(device_interface_data);
339     if (!SetupDiOpenDeviceInterface(dev_info.get(), device_path.c_str(), 0,
340                                     &device_interface_data)) {
341       USB_PLOG(ERROR) << "Failed to add device interface: " << device_path;
342       return;
343     }
344 
345     EnumerateDevice(dev_info.get(), &device_interface_data, device_path);
346   }
347 
EnumerateDevice(HDEVINFO dev_info,SP_DEVICE_INTERFACE_DATA * device_interface_data,const base::Optional<base::string16> & opt_device_path)348   void EnumerateDevice(HDEVINFO dev_info,
349                        SP_DEVICE_INTERFACE_DATA* device_interface_data,
350                        const base::Optional<base::string16>& opt_device_path) {
351     base::string16 device_path;
352     base::string16* device_path_ptr = &device_path;
353     if (opt_device_path) {
354       device_path = *opt_device_path;
355       device_path_ptr = nullptr;
356     }
357 
358     uint32_t bus_number;
359     uint32_t port_number;
360     base::string16 parent_instance_id;
361     std::vector<base::string16> child_instance_ids;
362     base::string16 service_name;
363     if (!GetDeviceInterfaceDetails(dev_info, device_interface_data,
364                                    device_path_ptr, &bus_number, &port_number,
365                                    &parent_instance_id, &child_instance_ids,
366                                    &service_name)) {
367       return;
368     }
369 
370     // For composite devices Windows loads the usbccgp driver, which creates
371     // child device notes for each of the device functions. It is these device
372     // paths for these children which must be opened in order to communicate
373     // with the WinUSB driver.
374     std::vector<base::string16> child_device_paths;
375     if (base::EqualsCaseInsensitiveASCII(service_name, L"usbccgp")) {
376       for (const base::string16& instance_id : child_instance_ids) {
377         base::string16 child_device_path;
378         if (GetWinUsbDevicePath(instance_id, &child_device_path))
379           child_device_paths.push_back(std::move(child_device_path));
380       }
381     }
382 
383     base::string16& hub_path = hub_paths_[parent_instance_id];
384     if (hub_path.empty()) {
385       base::string16 parent_path;
386       if (!GetDevicePath(parent_instance_id, GUID_DEVINTERFACE_USB_HUB,
387                          &parent_path)) {
388         return;
389       }
390       hub_path = parent_path;
391     }
392 
393     service_task_runner_->PostTask(
394         FROM_HERE, base::BindOnce(&UsbServiceWin::CreateDeviceObject, service_,
395                                   device_path, hub_path, child_device_paths,
396                                   bus_number, port_number, service_name));
397   }
398 
399  private:
400   std::unordered_map<base::string16, base::string16> hub_paths_;
401 
402   // Calls back to |service_| must be posted to |service_task_runner_|, which
403   // runs tasks on the thread where that object lives.
404   scoped_refptr<base::SingleThreadTaskRunner> service_task_runner_;
405   base::WeakPtr<UsbServiceWin> service_;
406 };
407 
UsbServiceWin()408 UsbServiceWin::UsbServiceWin()
409     : UsbService(),
410       blocking_task_runner_(CreateBlockingTaskRunner()),
411       helper_(nullptr, base::OnTaskRunnerDeleter(blocking_task_runner_)),
412       device_observer_(this) {
413   DeviceMonitorWin* device_monitor =
414       DeviceMonitorWin::GetForDeviceInterface(GUID_DEVINTERFACE_USB_DEVICE);
415   if (device_monitor)
416     device_observer_.Add(device_monitor);
417 
418   helper_.reset(new BlockingTaskRunnerHelper(weak_factory_.GetWeakPtr()));
419   blocking_task_runner_->PostTask(
420       FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::EnumerateDevices,
421                                 base::Unretained(helper_.get())));
422 }
423 
~UsbServiceWin()424 UsbServiceWin::~UsbServiceWin() {
425   NotifyWillDestroyUsbService();
426 }
427 
GetDevices(GetDevicesCallback callback)428 void UsbServiceWin::GetDevices(GetDevicesCallback callback) {
429   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
430   if (enumeration_ready())
431     UsbService::GetDevices(std::move(callback));
432   else
433     enumeration_callbacks_.push_back(std::move(callback));
434 }
435 
OnDeviceAdded(const GUID & class_guid,const base::string16 & device_path)436 void UsbServiceWin::OnDeviceAdded(const GUID& class_guid,
437                                   const base::string16& device_path) {
438   blocking_task_runner_->PostTask(
439       FROM_HERE, base::BindOnce(&BlockingTaskRunnerHelper::EnumerateDevicePath,
440                                 base::Unretained(helper_.get()), device_path));
441 }
442 
OnDeviceRemoved(const GUID & class_guid,const base::string16 & device_path)443 void UsbServiceWin::OnDeviceRemoved(const GUID& class_guid,
444                                     const base::string16& device_path) {
445   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
446   auto by_path_it = devices_by_path_.find(device_path);
447   if (by_path_it == devices_by_path_.end())
448     return;
449 
450   scoped_refptr<UsbDeviceWin> device = by_path_it->second;
451   devices_by_path_.erase(by_path_it);
452   device->OnDisconnect();
453 
454   auto by_guid_it = devices().find(device->guid());
455   if (by_guid_it != devices().end() && enumeration_ready()) {
456     USB_LOG(USER) << "USB device removed: path=" << device->device_path()
457                   << " guid=" << device->guid();
458 
459     devices().erase(by_guid_it);
460     NotifyDeviceRemoved(device);
461   }
462 }
463 
HelperStarted()464 void UsbServiceWin::HelperStarted() {
465   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
466   helper_started_ = true;
467   if (enumeration_ready()) {
468     std::vector<scoped_refptr<UsbDevice>> result;
469     result.reserve(devices().size());
470     for (const auto& map_entry : devices())
471       result.push_back(map_entry.second);
472     for (auto& callback : enumeration_callbacks_)
473       std::move(callback).Run(result);
474     enumeration_callbacks_.clear();
475   }
476 }
477 
CreateDeviceObject(const base::string16 & device_path,const base::string16 & hub_path,const std::vector<base::string16> & child_device_paths,uint32_t bus_number,uint32_t port_number,const base::string16 & driver_name)478 void UsbServiceWin::CreateDeviceObject(
479     const base::string16& device_path,
480     const base::string16& hub_path,
481     const std::vector<base::string16>& child_device_paths,
482     uint32_t bus_number,
483     uint32_t port_number,
484     const base::string16& driver_name) {
485   // Devices that appear during initial enumeration are gathered into the first
486   // result returned by GetDevices() and prevent device add/remove notifications
487   // from being sent.
488   if (!enumeration_ready())
489     ++first_enumeration_countdown_;
490 
491   auto device = base::MakeRefCounted<UsbDeviceWin>(
492       device_path, hub_path, child_device_paths, bus_number, port_number,
493       driver_name);
494   devices_by_path_[device->device_path()] = device;
495   device->ReadDescriptors(base::BindOnce(&UsbServiceWin::DeviceReady,
496                                          weak_factory_.GetWeakPtr(), device));
497 }
498 
DeviceReady(scoped_refptr<UsbDeviceWin> device,bool success)499 void UsbServiceWin::DeviceReady(scoped_refptr<UsbDeviceWin> device,
500                                 bool success) {
501   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
502 
503   bool enumeration_became_ready = false;
504   if (!enumeration_ready()) {
505     DCHECK_GT(first_enumeration_countdown_, 0u);
506     first_enumeration_countdown_--;
507     if (enumeration_ready())
508       enumeration_became_ready = true;
509   }
510 
511   // If |device| was disconnected while descriptors were being read then it
512   // will have been removed from |devices_by_path_|.
513   auto it = devices_by_path_.find(device->device_path());
514   if (it == devices_by_path_.end()) {
515     success = false;
516   } else if (success) {
517     DCHECK(!base::Contains(devices(), device->guid()));
518     devices()[device->guid()] = device;
519 
520     USB_LOG(USER) << "USB device added: path=" << device->device_path()
521                   << " vendor=" << device->vendor_id() << " \""
522                   << device->manufacturer_string()
523                   << "\", product=" << device->product_id() << " \""
524                   << device->product_string() << "\", serial=\""
525                   << device->serial_number() << "\", driver=\""
526                   << device->driver_name() << "\", children=["
527                   << base::JoinString(device->child_device_paths(), L", ")
528                   << "], guid=" << device->guid();
529   } else {
530     devices_by_path_.erase(it);
531   }
532 
533   if (enumeration_became_ready) {
534     std::vector<scoped_refptr<UsbDevice>> result;
535     result.reserve(devices().size());
536     for (const auto& map_entry : devices())
537       result.push_back(map_entry.second);
538     for (auto& callback : enumeration_callbacks_)
539       std::move(callback).Run(result);
540     enumeration_callbacks_.clear();
541   } else if (success && enumeration_ready()) {
542     NotifyDeviceAdded(device);
543   }
544 }
545 
546 }  // namespace device
547