diff options
Diffstat (limited to 'executor/common_usb.h')
| -rw-r--r-- | executor/common_usb.h | 132 |
1 files changed, 106 insertions, 26 deletions
diff --git a/executor/common_usb.h b/executor/common_usb.h index 34e3e3166..29196c2d0 100644 --- a/executor/common_usb.h +++ b/executor/common_usb.h @@ -28,7 +28,7 @@ struct usb_device_index { int iface_cur; }; -static bool parse_usb_descriptor(char* buffer, size_t length, struct usb_device_index* index) +static bool parse_usb_descriptor(const char* buffer, size_t length, struct usb_device_index* index) { if (length < sizeof(*index->dev) + sizeof(*index->config)) return false; @@ -193,7 +193,7 @@ struct usb_info { static struct usb_info usb_devices[MAX_USB_FDS]; static int usb_devices_num; -static struct usb_device_index* add_usb_index(int fd, char* dev, size_t dev_len) +static struct usb_device_index* add_usb_index(int fd, const char* dev, size_t dev_len) { int i = __atomic_fetch_add(&usb_devices_num, 1, __ATOMIC_RELAXED); if (i >= MAX_USB_FDS) @@ -708,7 +708,7 @@ static void analyze_control_request(int fd, struct usb_ctrlrequest* ctrl) #endif // USB_DEBUG -#define USB_MAX_PACKET_SIZE 1024 +#define USB_MAX_PACKET_SIZE 4096 struct usb_raw_control_event { struct usb_raw_event inner; @@ -745,8 +745,8 @@ static const char default_lang_id[] = { 0x09, 0x04 // English (United States) }; -static bool lookup_connect_response(int fd, struct vusb_connect_descriptors* descs, struct usb_ctrlrequest* ctrl, - char** response_data, uint32* response_length) +static bool lookup_connect_response_in(int fd, const struct vusb_connect_descriptors* descs, const struct usb_ctrlrequest* ctrl, + char** response_data, uint32* response_length) { struct usb_device_index* index = lookup_usb_index(fd); uint8 str_idx; @@ -807,30 +807,85 @@ static bool lookup_connect_response(int fd, struct vusb_connect_descriptors* des *response_length = descs->qual_len; return true; default: - fail("lookup_connect_response: no response"); - return false; + break; } break; default: - fail("lookup_connect_response: no response"); - return false; + break; } break; default: - fail("lookup_connect_response: no response"); - return false; + break; } + fail("lookup_connect_response_in: unknown request"); return false; } -static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatile long a2, volatile long a3) +#if SYZ_EXECUTOR || __NR_syz_usb_connect +static bool lookup_connect_response_out_generic(int fd, const struct vusb_connect_descriptors* descs, + const struct usb_ctrlrequest* ctrl, bool* done) { - uint64 speed = a0; - uint64 dev_len = a1; - char* dev = (char*)a2; - struct vusb_connect_descriptors* descs = (struct vusb_connect_descriptors*)a3; + switch (ctrl->bRequestType & USB_TYPE_MASK) { + case USB_TYPE_STANDARD: + switch (ctrl->bRequest) { + case USB_REQ_SET_CONFIGURATION: + *done = true; + return true; + default: + break; + } + break; + } + + fail("lookup_connect_response_out: unknown request"); + return false; +} +#endif + +#if SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k + +// drivers/net/wireless/ath/ath9k/hif_usb.h +#define ATH9K_FIRMWARE_DOWNLOAD 0x30 +#define ATH9K_FIRMWARE_DOWNLOAD_COMP 0x31 + +static bool lookup_connect_response_out_ath9k(int fd, const struct vusb_connect_descriptors* descs, + const struct usb_ctrlrequest* ctrl, bool* done) +{ + switch (ctrl->bRequestType & USB_TYPE_MASK) { + case USB_TYPE_STANDARD: + switch (ctrl->bRequest) { + case USB_REQ_SET_CONFIGURATION: + return true; + default: + break; + } + break; + case USB_TYPE_VENDOR: + switch (ctrl->bRequest) { + case ATH9K_FIRMWARE_DOWNLOAD: + return true; + case ATH9K_FIRMWARE_DOWNLOAD_COMP: + *done = true; + return true; + default: + break; + } + break; + } + + fail("lookup_connect_response_out_ath9k: unknown request"); + return false; +} +#endif + +typedef bool (*lookup_connect_response_t)(int fd, const struct vusb_connect_descriptors* descs, + const struct usb_ctrlrequest* ctrl, bool* done); + +static volatile long syz_usb_connect_impl(uint64 speed, uint64 dev_len, const char* dev, + const struct vusb_connect_descriptors* descs, lookup_connect_response_t lookup_connect_response_out) +{ debug("syz_usb_connect: dev: %p\n", dev); if (!dev) { debug("syz_usb_connect: dev is null\n"); @@ -902,26 +957,27 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatil analyze_control_request(fd, &event.ctrl); #endif - bool response_found = false; char* response_data = NULL; uint32 response_length = 0; if (event.ctrl.bRequestType & USB_DIR_IN) { - NONFAILING(response_found = lookup_connect_response(fd, descs, &event.ctrl, &response_data, &response_length)); + bool response_found = false; + NONFAILING(response_found = lookup_connect_response_in(fd, descs, &event.ctrl, &response_data, &response_length)); if (!response_found) { debug("syz_usb_connect: unknown control IN request\n"); return -1; } } else { - if ((event.ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD || - event.ctrl.bRequest != USB_REQ_SET_CONFIGURATION) { - fail("syz_usb_connect: unknown control OUT request"); + if (!lookup_connect_response_out(fd, descs, &event.ctrl, &done)) { + debug("syz_usb_connect: unknown control OUT request\n"); return -1; } - done = true; + response_data = NULL; + response_length = event.ctrl.wLength; } - if (done) { + if ((event.ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD && + event.ctrl.bRequest == USB_REQ_SET_CONFIGURATION) { rv = configure_device(fd); if (rv < 0) { debug("syz_usb_connect: configure_device failed with %d\n", rv); @@ -963,6 +1019,30 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatil return fd; } +#if SYZ_EXECUTOR || __NR_syz_usb_connect +static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatile long a2, volatile long a3) +{ + uint64 speed = a0; + uint64 dev_len = a1; + const char* dev = (const char*)a2; + const struct vusb_connect_descriptors* descs = (const struct vusb_connect_descriptors*)a3; + + return syz_usb_connect_impl(speed, dev_len, dev, descs, &lookup_connect_response_out_generic); +} +#endif + +#if SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k +static volatile long syz_usb_connect_ath9k(volatile long a0, volatile long a1, volatile long a2, volatile long a3) +{ + uint64 speed = a0; + uint64 dev_len = a1; + const char* dev = (const char*)a2; + const struct vusb_connect_descriptors* descs = (const struct vusb_connect_descriptors*)a3; + + return syz_usb_connect_impl(speed, dev_len, dev, descs, &lookup_connect_response_out_ath9k); +} +#endif + #if SYZ_EXECUTOR || __NR_syz_usb_control_io struct vusb_descriptor { uint8 req_type; @@ -990,7 +1070,7 @@ struct vusb_responses { struct vusb_response* resps[0]; } __attribute__((packed)); -static bool lookup_control_response(struct vusb_descriptors* descs, struct vusb_responses* resps, +static bool lookup_control_response(const struct vusb_descriptors* descs, const struct vusb_responses* resps, struct usb_ctrlrequest* ctrl, char** response_data, uint32* response_length) { int descs_num = 0; @@ -1057,8 +1137,8 @@ static bool lookup_control_response(struct vusb_descriptors* descs, struct vusb_ static volatile long syz_usb_control_io(volatile long a0, volatile long a1, volatile long a2) { int fd = a0; - struct vusb_descriptors* descs = (struct vusb_descriptors*)a1; - struct vusb_responses* resps = (struct vusb_responses*)a2; + const struct vusb_descriptors* descs = (const struct vusb_descriptors*)a1; + const struct vusb_responses* resps = (const struct vusb_responses*)a2; struct usb_raw_control_event event; event.inner.type = 0; |
