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