1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <err.h>
18 #include <stdio.h>
19 #include <unistd.h>
20 
21 #include <optional>
22 #include <string>
23 #include <vector>
24 
25 #include <libusb/libusb.h>
26 
is_adb_device(libusb_device * device)27 static bool is_adb_device(libusb_device* device) {
28     libusb_device_descriptor device_desc;
29     libusb_get_device_descriptor(device, &device_desc);
30     if (device_desc.bDeviceClass != 0) {
31         return false;
32     }
33 
34     libusb_config_descriptor* config_desc;
35     int rc = libusb_get_active_config_descriptor(device, &config_desc);
36     if (rc != 0) {
37         fprintf(stderr, "failed to get config descriptor for device %u:%u: %s\n",
38                 libusb_get_bus_number(device), libusb_get_port_number(device),
39                 libusb_error_name(rc));
40         return false;
41     }
42 
43     for (size_t i = 0; i < config_desc->bNumInterfaces; ++i) {
44         const libusb_interface* interface = &config_desc->interface[i];
45         for (int j = 0; j < interface->num_altsetting; ++j) {
46             const libusb_interface_descriptor* interface_descriptor = &interface->altsetting[j];
47             if (interface_descriptor->bInterfaceClass == 0xff &&
48                 interface_descriptor->bInterfaceSubClass == 0x42 &&
49                 interface_descriptor->bInterfaceProtocol == 1) {
50                 return true;
51             }
52         }
53     }
54 
55     return false;
56 }
57 
get_descriptor(libusb_device_handle * handle,uint8_t type,uint8_t index,uint16_t length)58 static std::optional<std::vector<uint8_t>> get_descriptor(libusb_device_handle* handle,
59                                                           uint8_t type, uint8_t index,
60                                                           uint16_t length) {
61     std::vector<uint8_t> result;
62     result.resize(length);
63     int rc = libusb_get_descriptor(handle, type, index, result.data(), result.size());
64     if (rc < 0) {
65         fprintf(stderr, "libusb_get_descriptor failed: %s\n", libusb_error_name(rc));
66         return std::nullopt;
67     }
68     result.resize(rc);
69     return result;
70 }
71 
get_string_descriptor(libusb_device_handle * handle,uint8_t index)72 static std::optional<std::string> get_string_descriptor(libusb_device_handle* handle,
73                                                         uint8_t index) {
74     std::string result;
75     result.resize(4096);
76     int rc = libusb_get_string_descriptor_ascii(
77             handle, index, reinterpret_cast<uint8_t*>(result.data()), result.size());
78     if (rc < 0) {
79         fprintf(stderr, "libusb_get_string_descriptor_ascii failed: %s\n", libusb_error_name(rc));
80         return std::nullopt;
81     }
82     result.resize(rc);
83     return result;
84 }
85 
check_ms_os_desc_v1(libusb_device_handle * device_handle,const std::string & serial)86 static void check_ms_os_desc_v1(libusb_device_handle* device_handle, const std::string& serial) {
87     auto os_desc = get_descriptor(device_handle, 0x03, 0xEE, 0x12);
88     if (!os_desc) {
89         errx(1, "failed to retrieve MS OS descriptor");
90     }
91 
92     if (os_desc->size() != 0x12) {
93         errx(1, "os descriptor size mismatch");
94     }
95 
96     if (memcmp(os_desc->data() + 2, u"MSFT100\0", 14) != 0) {
97         errx(1, "os descriptor signature mismatch");
98     }
99 
100     uint8_t vendor_code = (*os_desc)[16];
101     uint8_t pad = (*os_desc)[17];
102 
103     if (pad != 0) {
104         errx(1, "os descriptor padding non-zero");
105     }
106 
107     std::vector<uint8_t> data;
108     data.resize(0x10);
109     int rc = libusb_control_transfer(device_handle, 0xC0, vendor_code, 0x00, 0x04, data.data(),
110                                      data.size(), 0);
111     if (rc != 0x10) {
112         errx(1, "failed to retrieve MS OS v1 compat descriptor header: %s", libusb_error_name(rc));
113     }
114 
115     struct __attribute__((packed)) ms_os_desc_v1_header {
116         uint32_t dwLength;
117         uint16_t bcdVersion;
118         uint16_t wIndex;
119         uint8_t bCount;
120         uint8_t reserved[7];
121     };
122     static_assert(sizeof(ms_os_desc_v1_header) == 0x10);
123 
124     ms_os_desc_v1_header hdr;
125     memcpy(&hdr, data.data(), data.size());
126 
127     data.resize(hdr.dwLength);
128     rc = libusb_control_transfer(device_handle, 0xC0, vendor_code, 0x00, 0x04, data.data(),
129                                  data.size(), 0);
130     if (static_cast<size_t>(rc) != data.size()) {
131         errx(1, "failed to retrieve MS OS v1 compat descriptor: %s", libusb_error_name(rc));
132     }
133 
134     struct __attribute__((packed)) ms_os_desc_v1_function {
135         uint8_t bFirstInterfaceNumber;
136         uint8_t reserved1;
137         uint8_t compatibleID[8];
138         uint8_t subCompatibleID[8];
139         uint8_t reserved2[6];
140     };
141 
142     if (sizeof(ms_os_desc_v1_header) + hdr.bCount * sizeof(ms_os_desc_v1_function) != data.size()) {
143         errx(1, "MS OS v1 compat descriptor size mismatch");
144     }
145 
146     for (int i = 0; i < hdr.bCount; ++i) {
147         ms_os_desc_v1_function function;
148         memcpy(&function,
149                data.data() + sizeof(ms_os_desc_v1_header) + i * sizeof(ms_os_desc_v1_function),
150                sizeof(function));
151         if (memcmp("WINUSB\0\0", function.compatibleID, 8) == 0) {
152             return;
153         }
154     }
155 
156     errx(1, "failed to find v1 MS OS descriptor specifying WinUSB for device %s", serial.c_str());
157 }
158 
check_ms_os_desc_v2(libusb_device_handle * device_handle,const std::string & serial)159 static void check_ms_os_desc_v2(libusb_device_handle* device_handle, const std::string& serial) {
160     libusb_bos_descriptor* bos;
161     int rc = libusb_get_bos_descriptor(device_handle, &bos);
162 
163     if (rc != 0) {
164         fprintf(stderr, "failed to get bos descriptor for device %s\n", serial.c_str());
165         return;
166     }
167 
168     for (size_t i = 0; i < bos->bNumDeviceCaps; ++i) {
169         libusb_bos_dev_capability_descriptor* desc = bos->dev_capability[i];
170         if (desc->bDescriptorType != LIBUSB_DT_DEVICE_CAPABILITY) {
171             errx(1, "invalid BOS descriptor type: %d", desc->bDescriptorType);
172         }
173 
174         if (desc->bDevCapabilityType != 0x05 /* PLATFORM */) {
175             fprintf(stderr, "skipping non-platform dev capability: %#02x\n",
176                     desc->bDevCapabilityType);
177             continue;
178         }
179 
180         if (desc->bLength < sizeof(*desc) + 16) {
181             errx(1, "received device capability descriptor not long enough to contain a UUID?");
182         }
183 
184         char uuid[16];
185         memcpy(uuid, desc->dev_capability_data, 16);
186 
187         constexpr uint8_t ms_os_uuid[16] = {0xD8, 0xDD, 0x60, 0xDF, 0x45, 0x89, 0x4C, 0xC7,
188                                             0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F};
189         if (memcmp(uuid, ms_os_uuid, 16) != 0) {
190             fprintf(stderr, "skipping unknown UUID\n");
191             continue;
192         }
193 
194         size_t data_length = desc->bLength - sizeof(*desc) - 16;
195         fprintf(stderr, "found MS OS 2.0 descriptor, length = %zu\n", data_length);
196 
197         // Linux does not appear to support MS OS 2.0 Descriptors.
198         // TODO: If and when it does, verify that we're emitting them properly.
199     }
200 }
201 
main(int argc,char ** argv)202 int main(int argc, char** argv) {
203     libusb_context* ctx;
204     if (libusb_init(&ctx) != 0) {
205         errx(1, "failed to initialize libusb context");
206     }
207 
208     libusb_device** device_list = nullptr;
209     ssize_t device_count = libusb_get_device_list(ctx, &device_list);
210     if (device_count < 0) {
211         errx(1, "libusb_get_device_list failed");
212     }
213 
214     const char* expected_serial = getenv("ANDROID_SERIAL");
215     bool found = false;
216 
217     for (ssize_t i = 0; i < device_count; ++i) {
218         libusb_device* device = device_list[i];
219         if (!is_adb_device(device)) {
220             continue;
221         }
222 
223         libusb_device_handle* device_handle = nullptr;
224         int rc = libusb_open(device, &device_handle);
225         if (rc != 0) {
226             fprintf(stderr, "failed to open device %u:%u: %s\n", libusb_get_bus_number(device),
227                     libusb_get_port_number(device), libusb_error_name(rc));
228             continue;
229         }
230 
231         libusb_device_descriptor device_desc;
232         libusb_get_device_descriptor(device, &device_desc);
233 
234         std::optional<std::string> serial =
235                 get_string_descriptor(device_handle, device_desc.iSerialNumber);
236         if (!serial) {
237             errx(1, "failed to get serial for device %u:%u", libusb_get_bus_number(device),
238                  libusb_get_port_number(device));
239         }
240 
241         if (expected_serial && *serial != expected_serial) {
242             fprintf(stderr, "skipping %s (wanted %s)\n", serial->c_str(), expected_serial);
243             continue;
244         }
245 
246         // Check for MS OS Descriptor v1.
247         // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeusb/c2f351f9-84d2-4a1b-9fe3-a6ca195f84d0
248         fprintf(stderr, "fetching v1 OS descriptor from device %s\n", serial->c_str());
249         check_ms_os_desc_v1(device_handle, *serial);
250         fprintf(stderr, "found v1 OS descriptor for device %s\n", serial->c_str());
251 
252         // Read BOS for MS OS Descriptor 2.0 descriptors:
253         // http://download.microsoft.com/download/3/5/6/3563ED4A-F318-4B66-A181-AB1D8F6FD42D/MS_OS_2_0_desc.docx
254         fprintf(stderr, "fetching v2 OS descriptor from device %s\n", serial->c_str());
255         check_ms_os_desc_v2(device_handle, *serial);
256 
257         found = true;
258     }
259 
260     if (expected_serial && !found) {
261         errx(1, "failed to find device with serial %s", expected_serial);
262     }
263     return 0;
264 }
265