github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/executor/common_usb_netbsd.h (about) 1 // Copyright 2020 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 // This file is shared between executor and csource package. 5 6 // NetBSD-specific implementation of syz_usb_* pseudo-syscalls. 7 8 #include <dev/usb/usb.h> 9 #include <dev/usb/usbhid.h> 10 #include <dev/usb/vhci.h> 11 #include <fcntl.h> 12 #include <sys/ioctl.h> 13 14 // Redefinitions to match the linux types used in common_usb.h. 15 16 struct usb_endpoint_descriptor { 17 uint8 bLength; 18 uint8 bDescriptorType; 19 uint8 bEndpointAddress; 20 uint8 bmAttributes; 21 uint16 wMaxPacketSize; 22 uint8 bInterval; 23 uint8 bRefresh; 24 uint8 bSynchAddress; 25 } __attribute__((packed)); 26 27 struct usb_device_descriptor { 28 uint8 bLength; 29 uint8 bDescriptorType; 30 uint16 bcdUSB; 31 uint8 bDeviceClass; 32 uint8 bDeviceSubClass; 33 uint8 bDeviceProtocol; 34 uint8 bMaxPacketSize0; 35 uint16 idVendor; 36 uint16 idProduct; 37 uint16 bcdDevice; 38 uint8 iManufacturer; 39 uint8 iProduct; 40 uint8 iSerialNumber; 41 uint8 bNumConfigurations; 42 } __attribute__((packed)); 43 44 struct usb_config_descriptor { 45 uint8 bLength; 46 uint8 bDescriptorType; 47 48 uint16 wTotalLength; 49 uint8 bNumInterfaces; 50 uint8 bConfigurationValue; 51 uint8 iConfiguration; 52 uint8 bmAttributes; 53 uint8 bMaxPower; 54 } __attribute__((packed)); 55 56 struct usb_interface_descriptor { 57 uint8 bLength; 58 uint8 bDescriptorType; 59 uint8 bInterfaceNumber; 60 uint8 bAlternateSetting; 61 uint8 bNumEndpoints; 62 uint8 bInterfaceClass; 63 uint8 bInterfaceSubClass; 64 uint8 bInterfaceProtocol; 65 uint8 iInterface; 66 } __attribute__((packed)); 67 68 struct usb_ctrlrequest { 69 uint8 bRequestType; 70 uint8 bRequest; 71 uint16 wValue; 72 uint16 wIndex; 73 uint16 wLength; 74 } __attribute__((packed)); 75 76 struct usb_qualifier_descriptor { 77 uint8 bLength; 78 uint8 bDescriptorType; 79 uint16 bcdUSB; 80 uint8 bDeviceClass; 81 uint8 bDeviceSubClass; 82 uint8 bDeviceProtocol; 83 uint8 bMaxPacketSize0; 84 uint8 bNumConfigurations; 85 uint8 bRESERVED; 86 } __attribute__((packed)); 87 88 #define USB_TYPE_MASK (0x03 << 5) 89 #define USB_TYPE_STANDARD (0x00 << 5) 90 #define USB_TYPE_CLASS (0x01 << 5) 91 #define USB_TYPE_VENDOR (0x02 << 5) 92 #define USB_TYPE_RESERVED (0x03 << 5) 93 94 #define USB_DT_DEVICE 0x01 95 #define USB_DT_CONFIG 0x02 96 #define USB_DT_STRING 0x03 97 #define USB_DT_INTERFACE 0x04 98 #define USB_DT_ENDPOINT 0x05 99 #define USB_DT_DEVICE_QUALIFIER 0x06 100 #define USB_DT_OTHER_SPEED_CONFIG 0x07 101 #define USB_DT_INTERFACE_POWER 0x08 102 #define USB_DT_OTG 0x09 103 #define USB_DT_DEBUG 0x0a 104 #define USB_DT_INTERFACE_ASSOCIATION 0x0b 105 #define USB_DT_SECURITY 0x0c 106 #define USB_DT_KEY 0x0d 107 #define USB_DT_ENCRYPTION_TYPE 0x0e 108 #define USB_DT_BOS 0x0f 109 #define USB_DT_DEVICE_CAPABILITY 0x10 110 #define USB_DT_WIRELESS_ENDPOINT_COMP 0x11 111 #define USB_DT_WIRE_ADAPTER 0x21 112 #define USB_DT_RPIPE 0x22 113 #define USB_DT_CS_RADIO_CONTROL 0x23 114 #define USB_DT_PIPE_USAGE 0x24 115 #define USB_DT_SS_ENDPOINT_COMP 0x30 116 #define USB_DT_SSP_ISOC_ENDPOINT_COMP 0x31 117 118 #define USB_REQ_GET_STATUS 0x00 119 #define USB_REQ_CLEAR_FEATURE 0x01 120 #define USB_REQ_SET_FEATURE 0x03 121 #define USB_REQ_SET_ADDRESS 0x05 122 #define USB_REQ_GET_DESCRIPTOR 0x06 123 #define USB_REQ_SET_DESCRIPTOR 0x07 124 #define USB_REQ_GET_CONFIGURATION 0x08 125 #define USB_REQ_SET_CONFIGURATION 0x09 126 #define USB_REQ_GET_INTERFACE 0x0A 127 #define USB_REQ_SET_INTERFACE 0x0B 128 #define USB_REQ_SYNCH_FRAME 0x0C 129 #define USB_REQ_SET_SEL 0x30 130 #define USB_REQ_SET_ISOCH_DELAY 0x31 131 132 #define USB_REQ_SET_ENCRYPTION 0x0D 133 #define USB_REQ_GET_ENCRYPTION 0x0E 134 #define USB_REQ_RPIPE_ABORT 0x0E 135 #define USB_REQ_SET_HANDSHAKE 0x0F 136 #define USB_REQ_RPIPE_RESET 0x0F 137 #define USB_REQ_GET_HANDSHAKE 0x10 138 #define USB_REQ_SET_CONNECTION 0x11 139 #define USB_REQ_SET_SECURITY_DATA 0x12 140 #define USB_REQ_GET_SECURITY_DATA 0x13 141 #define USB_REQ_SET_WUSB_DATA 0x14 142 #define USB_REQ_LOOPBACK_DATA_WRITE 0x15 143 #define USB_REQ_LOOPBACK_DATA_READ 0x16 144 #define USB_REQ_SET_INTERFACE_DS 0x17 145 146 #define USB_REQ_GET_PARTNER_PDO 20 147 #define USB_REQ_GET_BATTERY_STATUS 21 148 #define USB_REQ_SET_PDO 22 149 #define USB_REQ_GET_VDM 23 150 #define USB_REQ_SEND_VDM 24 151 152 #if SYZ_EXECUTOR || __NR_syz_usb_connect 153 #include "common_usb.h" 154 155 static int vhci_open(void) 156 { 157 char path[1024]; 158 159 snprintf(path, sizeof(path), "/dev/vhci%llu", procid); 160 161 return open(path, O_RDWR); 162 } 163 164 static int vhci_setport(int fd, u_int port) 165 { 166 struct vhci_ioc_set_port args; 167 168 args.port = port; 169 return ioctl(fd, VHCI_IOC_SET_PORT, &args); 170 } 171 172 static int vhci_usb_attach(int fd) 173 { 174 return ioctl(fd, VHCI_IOC_USB_ATTACH, NULL); 175 } 176 177 static int vhci_usb_recv(int fd, void* buf, size_t size) 178 { 179 uint8* ptr = (uint8*)buf; 180 181 while (1) { 182 ssize_t done = read(fd, ptr, size); 183 if (done < 0) 184 return -1; 185 if ((size_t)done == size) 186 return 0; 187 size -= done; 188 ptr += done; 189 } 190 } 191 192 static int vhci_usb_send(int fd, void* buf, size_t size) 193 { 194 uint8* ptr = (uint8*)buf; 195 196 while (1) { 197 ssize_t done = write(fd, ptr, size); 198 if (done <= 0) 199 return -1; 200 if ((size_t)done == size) 201 return 0; 202 size -= done; 203 ptr += done; 204 } 205 } 206 207 static volatile long syz_usb_connect_impl(int fd, uint64 speed, uint64 dev_len, 208 const char* dev, const struct vusb_connect_descriptors* descs, 209 lookup_connect_out_response_t lookup_connect_response_out) 210 { 211 struct usb_device_index* index = add_usb_index(fd, dev, dev_len); 212 if (!index) { 213 debug("syz_usb_connect: add_usb_index failed\n"); 214 return -1; 215 } 216 debug("syz_usb_connect: add_usb_index success\n"); 217 218 #if USB_DEBUG 219 analyze_usb_device(index); 220 #endif 221 222 if (vhci_setport(fd, 1)) 223 fail("syz_usb_connect: vhci_setport failed with"); 224 225 if (vhci_usb_attach(fd)) { 226 debug("syz_usb_connect: vhci_usb_attach failed with %d\n", errno); 227 return -1; 228 } 229 debug("syz_usb_connect: vhci_usb_attach success\n"); 230 231 bool done = false; 232 while (!done) { 233 vhci_request_t req; 234 235 if (vhci_usb_recv(fd, &req, sizeof(req))) { 236 debug("syz_usb_connect: vhci_usb_recv failed with %d\n", errno); 237 return -1; 238 } 239 if (req.type != VHCI_REQ_CTRL) { 240 debug("syz_usb_connect: received non-control transfer\n"); 241 return -1; 242 } 243 244 debug("syz_usb_connect: bReqType: 0x%x (%s), bReq: 0x%x, wVal: 0x%x, wIdx: 0x%x, wLen: %d\n", 245 req.u.ctrl.bmRequestType, (req.u.ctrl.bmRequestType & UE_DIR_IN) ? "IN" : "OUT", 246 req.u.ctrl.bRequest, UGETW(req.u.ctrl.wValue), UGETW(req.u.ctrl.wIndex), UGETW(req.u.ctrl.wLength)); 247 248 #if USB_DEBUG 249 analyze_control_request(fd, &req.u.ctrl); 250 #endif 251 252 char* response_data = NULL; 253 uint32 response_length = 0; 254 struct usb_qualifier_descriptor qual; 255 char data[4096]; 256 257 if (req.u.ctrl.bmRequestType & UE_DIR_IN) { 258 if (!lookup_connect_response_in(fd, descs, (const struct usb_ctrlrequest*)&req.u.ctrl, &qual, &response_data, &response_length)) { 259 debug("syz_usb_connect: unknown control IN request\n"); 260 return -1; 261 } 262 } else { 263 if (!lookup_connect_response_out(fd, descs, (const struct usb_ctrlrequest*)&req.u.ctrl, &done)) { 264 debug("syz_usb_connect: unknown control OUT request\n"); 265 return -1; 266 } 267 response_data = NULL; 268 response_length = UGETW(req.u.ctrl.wLength); 269 } 270 271 if ((req.u.ctrl.bmRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD && 272 req.u.ctrl.bRequest == USB_REQ_SET_CONFIGURATION) { 273 } // TODO: possibly revisit. 274 275 if (response_length > sizeof(data)) 276 response_length = 0; 277 if ((uint32)UGETW(req.u.ctrl.wLength) < response_length) 278 response_length = UGETW(req.u.ctrl.wLength); 279 280 if (response_data) 281 memcpy(data, response_data, response_length); 282 else 283 memset(data, 0, response_length); 284 285 int rv = 0; 286 if (req.u.ctrl.bmRequestType & UE_DIR_IN) { 287 debug("syz_usb_connect: writing %d bytes\n", response_length); 288 if (response_length > 0) { 289 vhci_response_t res; 290 res.size = response_length; 291 rv = vhci_usb_send(fd, &res, sizeof(res)); 292 if (rv == 0) 293 rv = vhci_usb_send(fd, data, response_length); 294 } 295 } else { 296 rv = vhci_usb_recv(fd, data, response_length); 297 debug("syz_usb_connect: read %d bytes\n", response_length); 298 debug_dump_data(&data[0], response_length); 299 } 300 if (rv < 0) { 301 debug("syz_usb_connect: usb_raw_ep0_read/write failed with %d\n", rv); 302 return -1; 303 } 304 } 305 306 sleep_ms(200); 307 debug("syz_usb_connect: configured\n"); 308 return fd; 309 } 310 311 static volatile long syz_usb_connect(volatile long a0, volatile long a1, 312 volatile long a2, volatile long a3) 313 { 314 uint64 speed = a0; 315 uint64 dev_len = a1; 316 const char* dev = (const char*)a2; 317 const struct vusb_connect_descriptors* descs = (const struct vusb_connect_descriptors*)a3; 318 319 debug("syz_usb_connect: dev: %p\n", dev); 320 if (!dev) { 321 debug("syz_usb_connect: dev is null\n"); 322 return -1; 323 } 324 325 debug("syz_usb_connect: device data:\n"); 326 debug_dump_data(dev, dev_len); 327 328 int fd = vhci_open(); 329 if (fd < 0) 330 fail("syz_usb_connect: vhci_open failed"); 331 long res = syz_usb_connect_impl(fd, speed, dev_len, dev, descs, &lookup_connect_response_out_generic); 332 close(fd); 333 return res; 334 } 335 #endif // SYZ_EXECUTOR || __NR_syz_usb_connect 336 337 #if SYZ_EXECUTOR || __NR_syz_usb_disconnect 338 static volatile long syz_usb_disconnect(volatile long a0) 339 { 340 int fd = a0; 341 342 int rv = close(fd); 343 344 sleep_ms(200); 345 346 return rv; 347 } 348 #endif // SYZ_EXECUTOR || __NR_syz_usb_disconnect