diff options
| author | Andrey Konovalov <andreyknvl@google.com> | 2020-03-27 17:48:54 +0100 |
|---|---|---|
| committer | Andrey Konovalov <andreyknvl@gmail.com> | 2020-03-28 11:53:20 +0100 |
| commit | 47232600c37df6b12e2081af1c86ff1c693e4cbb (patch) | |
| tree | 36b8d583869e4e236ac7cf018826e1dcef27481a /executor/common_usb.h | |
| parent | 831e9a81a60573f12c44f35c7b04072f41854bdf (diff) | |
executor: split out Linux specific USB code
Diffstat (limited to 'executor/common_usb.h')
| -rw-r--r-- | executor/common_usb.h | 560 |
1 files changed, 27 insertions, 533 deletions
diff --git a/executor/common_usb.h b/executor/common_usb.h index 29196c2d0..06cb36967 100644 --- a/executor/common_usb.h +++ b/executor/common_usb.h @@ -1,12 +1,13 @@ -// Copyright 2019 syzkaller project authors. All rights reserved. +// Copyright 2020 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. // This file is shared between executor and csource package. -// Implementation of syz_usb_* pseudo-syscalls. +// Generic parts of implementation of syz_usb_* pseudo-syscalls. #define USB_MAX_IFACE_NUM 4 #define USB_MAX_EP_NUM 32 +#define USB_MAX_FDS 6 struct usb_iface_index { struct usb_interface_descriptor* iface; @@ -28,6 +29,14 @@ struct usb_device_index { int iface_cur; }; +struct usb_info { + int fd; + struct usb_device_index index; +}; + +static struct usb_info usb_devices[USB_MAX_FDS]; +static int usb_devices_num; + static bool parse_usb_descriptor(const char* buffer, size_t length, struct usb_device_index* index) { if (length < sizeof(*index->dev) + sizeof(*index->config)) @@ -76,127 +85,10 @@ static bool parse_usb_descriptor(const char* buffer, size_t length, struct usb_d return true; } -#define UDC_NAME_LENGTH_MAX 128 - -struct usb_raw_init { - __u8 driver_name[UDC_NAME_LENGTH_MAX]; - __u8 device_name[UDC_NAME_LENGTH_MAX]; - __u8 speed; -}; - -enum usb_raw_event_type { - USB_RAW_EVENT_INVALID = 0, - USB_RAW_EVENT_CONNECT = 1, - USB_RAW_EVENT_CONTROL = 2, -}; - -struct usb_raw_event { - __u32 type; - __u32 length; - __u8 data[0]; -}; - -struct usb_raw_ep_io { - __u16 ep; - __u16 flags; - __u32 length; - __u8 data[0]; -}; - -#define USB_RAW_IOCTL_INIT _IOW('U', 0, struct usb_raw_init) -#define USB_RAW_IOCTL_RUN _IO('U', 1) -#define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event) -#define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io) -#define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io) -#define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor) -#define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32) -#define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io) -#define USB_RAW_IOCTL_EP_READ _IOWR('U', 8, struct usb_raw_ep_io) -#define USB_RAW_IOCTL_CONFIGURE _IO('U', 9) -#define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32) - -static int usb_raw_open() -{ - return open("/dev/raw-gadget", O_RDWR); -} - -static int usb_raw_init(int fd, uint32 speed, const char* driver, const char* device) -{ - struct usb_raw_init arg; - strncpy((char*)&arg.driver_name[0], driver, sizeof(arg.driver_name)); - strncpy((char*)&arg.device_name[0], device, sizeof(arg.device_name)); - arg.speed = speed; - return ioctl(fd, USB_RAW_IOCTL_INIT, &arg); -} - -static int usb_raw_run(int fd) -{ - return ioctl(fd, USB_RAW_IOCTL_RUN, 0); -} - -static int usb_raw_event_fetch(int fd, struct usb_raw_event* event) -{ - return ioctl(fd, USB_RAW_IOCTL_EVENT_FETCH, event); -} - -static int usb_raw_ep0_write(int fd, struct usb_raw_ep_io* io) -{ - return ioctl(fd, USB_RAW_IOCTL_EP0_WRITE, io); -} - -static int usb_raw_ep0_read(int fd, struct usb_raw_ep_io* io) -{ - return ioctl(fd, USB_RAW_IOCTL_EP0_READ, io); -} - -#if SYZ_EXECUTOR || __NR_syz_usb_ep_write -static int usb_raw_ep_write(int fd, struct usb_raw_ep_io* io) -{ - return ioctl(fd, USB_RAW_IOCTL_EP_WRITE, io); -} -#endif - -#if SYZ_EXECUTOR || __NR_syz_usb_ep_read -static int usb_raw_ep_read(int fd, struct usb_raw_ep_io* io) -{ - return ioctl(fd, USB_RAW_IOCTL_EP_READ, io); -} -#endif - -static int usb_raw_ep_enable(int fd, struct usb_endpoint_descriptor* desc) -{ - return ioctl(fd, USB_RAW_IOCTL_EP_ENABLE, desc); -} - -static int usb_raw_ep_disable(int fd, int ep) -{ - return ioctl(fd, USB_RAW_IOCTL_EP_DISABLE, ep); -} - -static int usb_raw_configure(int fd) -{ - return ioctl(fd, USB_RAW_IOCTL_CONFIGURE, 0); -} - -static int usb_raw_vbus_draw(int fd, uint32 power) -{ - return ioctl(fd, USB_RAW_IOCTL_VBUS_DRAW, power); -} - -#define MAX_USB_FDS 6 - -struct usb_info { - int fd; - struct usb_device_index index; -}; - -static struct usb_info usb_devices[MAX_USB_FDS]; -static int usb_devices_num; - 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) + if (i >= USB_MAX_FDS) return NULL; int rv = 0; @@ -211,7 +103,7 @@ static struct usb_device_index* add_usb_index(int fd, const char* dev, size_t de static struct usb_device_index* lookup_usb_index(int fd) { int i; - for (i = 0; i < MAX_USB_FDS; i++) { + for (i = 0; i < USB_MAX_FDS; i++) { if (__atomic_load_n(&usb_devices[i].fd, __ATOMIC_ACQUIRE) == fd) { return &usb_devices[i].index; } @@ -219,76 +111,6 @@ static struct usb_device_index* lookup_usb_index(int fd) return NULL; } -#if SYZ_EXECUTOR || __NR_syz_usb_control_io -static int lookup_interface(int fd, uint8 bInterfaceNumber, uint8 bAlternateSetting) -{ - struct usb_device_index* index = lookup_usb_index(fd); - int i; - - if (!index) - return -1; - - for (i = 0; i < index->ifaces_num; i++) { - if (index->ifaces[i].bInterfaceNumber == bInterfaceNumber && - index->ifaces[i].bAlternateSetting == bAlternateSetting) - return i; - } - return -1; -} -#endif - -static void set_interface(int fd, int n) -{ - struct usb_device_index* index = lookup_usb_index(fd); - int ep; - - if (!index) - return; - - if (index->iface_cur >= 0 && index->iface_cur < index->ifaces_num) { - for (ep = 0; ep < index->ifaces[index->iface_cur].eps_num; ep++) { - int rv = usb_raw_ep_disable(fd, ep); - if (rv < 0) { - debug("set_interface: failed to disable endpoint %d\n", ep); - } else { - debug("set_interface: endpoint %d disabled\n", ep); - } - } - } - if (n >= 0 && n < index->ifaces_num) { - for (ep = 0; ep < index->ifaces[n].eps_num; ep++) { - int rv = usb_raw_ep_enable(fd, &index->ifaces[n].eps[ep]); - if (rv < 0) { - debug("set_interface: failed to enable endpoint %d\n", ep); - } else { - debug("set_interface: endpoint %d enabled as %d\n", ep, rv); - } - } - index->iface_cur = n; - } -} - -static int configure_device(int fd) -{ - struct usb_device_index* index = lookup_usb_index(fd); - - if (!index) - return -1; - - int rv = usb_raw_vbus_draw(fd, index->bMaxPower); - if (rv < 0) { - debug("configure_device: usb_raw_vbus_draw failed with %d\n", rv); - return rv; - } - rv = usb_raw_configure(fd); - if (rv < 0) { - debug("configure_device: usb_raw_configure failed with %d\n", rv); - return rv; - } - set_interface(fd, 0); - return 0; -} - #if USB_DEBUG #include <linux/hid.h> @@ -708,19 +530,6 @@ static void analyze_control_request(int fd, struct usb_ctrlrequest* ctrl) #endif // USB_DEBUG -#define USB_MAX_PACKET_SIZE 4096 - -struct usb_raw_control_event { - struct usb_raw_event inner; - struct usb_ctrlrequest ctrl; - char data[USB_MAX_PACKET_SIZE]; -}; - -struct usb_raw_ep_io_data { - struct usb_raw_ep_io inner; - char data[USB_MAX_PACKET_SIZE]; -}; - struct vusb_connect_string_descriptor { uint32 len; char* str; @@ -745,7 +554,8 @@ static const char default_lang_id[] = { 0x09, 0x04 // English (United States) }; -static bool lookup_connect_response_in(int fd, const struct vusb_connect_descriptors* descs, const struct usb_ctrlrequest* ctrl, +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); @@ -822,6 +632,9 @@ static bool lookup_connect_response_in(int fd, const struct vusb_connect_descrip return false; } +typedef bool (*lookup_connect_out_response_t)(int fd, const struct vusb_connect_descriptors* descs, + const struct usb_ctrlrequest* ctrl, bool* done); + #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) @@ -841,7 +654,7 @@ static bool lookup_connect_response_out_generic(int fd, const struct vusb_connec fail("lookup_connect_response_out: unknown request"); return false; } -#endif +#endif // SYZ_EXECUTOR || __NR_syz_usb_connect #if SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k @@ -878,172 +691,10 @@ static bool lookup_connect_response_out_ath9k(int fd, const struct vusb_connect_ 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"); - return -1; - } - - debug("syz_usb_connect: device data:\n"); - debug_dump_data(dev, dev_len); - - int fd = usb_raw_open(); - if (fd < 0) { - debug("syz_usb_connect: usb_raw_open failed with %d\n", fd); - return fd; - } - if (fd >= MAX_FDS) { - close(fd); - debug("syz_usb_connect: too many open fds\n"); - return -1; - } - debug("syz_usb_connect: usb_raw_open success\n"); - - struct usb_device_index* index = add_usb_index(fd, dev, dev_len); - if (!index) { - debug("syz_usb_connect: add_usb_index failed\n"); - return -1; - } - debug("syz_usb_connect: add_usb_index success\n"); - -#if USB_DEBUG - NONFAILING(analyze_usb_device(index)); -#endif - - // TODO: consider creating two dummy_udc's per proc to increace the chance of - // triggering interaction between multiple USB devices within the same program. - char device[32]; - sprintf(&device[0], "dummy_udc.%llu", procid); - int rv = usb_raw_init(fd, speed, "dummy_udc", &device[0]); - if (rv < 0) { - debug("syz_usb_connect: usb_raw_init failed with %d\n", rv); - return rv; - } - debug("syz_usb_connect: usb_raw_init success\n"); - - rv = usb_raw_run(fd); - if (rv < 0) { - debug("syz_usb_connect: usb_raw_run failed with %d\n", rv); - return rv; - } - debug("syz_usb_connect: usb_raw_run success\n"); - - bool done = false; - while (!done) { - struct usb_raw_control_event event; - event.inner.type = 0; - event.inner.length = sizeof(event.ctrl); - rv = usb_raw_event_fetch(fd, (struct usb_raw_event*)&event); - if (rv < 0) { - debug("syz_usb_connect: usb_raw_event_fetch failed with %d\n", rv); - return rv; - } - if (event.inner.type != USB_RAW_EVENT_CONTROL) - continue; - - debug("syz_usb_connect: bReqType: 0x%x (%s), bReq: 0x%x, wVal: 0x%x, wIdx: 0x%x, wLen: %d\n", - event.ctrl.bRequestType, (event.ctrl.bRequestType & USB_DIR_IN) ? "IN" : "OUT", - event.ctrl.bRequest, event.ctrl.wValue, event.ctrl.wIndex, event.ctrl.wLength); - -#if USB_DEBUG - analyze_control_request(fd, &event.ctrl); -#endif - - char* response_data = NULL; - uint32 response_length = 0; - - if (event.ctrl.bRequestType & USB_DIR_IN) { - 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 (!lookup_connect_response_out(fd, descs, &event.ctrl, &done)) { - debug("syz_usb_connect: unknown control OUT request\n"); - return -1; - } - response_data = NULL; - response_length = event.ctrl.wLength; - } - - 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); - return rv; - } - } - - struct usb_raw_ep_io_data response; - response.inner.ep = 0; - response.inner.flags = 0; - if (response_length > sizeof(response.data)) - response_length = 0; - if (event.ctrl.wLength < response_length) - response_length = event.ctrl.wLength; - response.inner.length = response_length; - if (response_data) - memcpy(&response.data[0], response_data, response_length); - else - memset(&response.data[0], 0, response_length); - - if (event.ctrl.bRequestType & USB_DIR_IN) { - debug("syz_usb_connect: writing %d bytes\n", response.inner.length); - rv = usb_raw_ep0_write(fd, (struct usb_raw_ep_io*)&response); - } else { - rv = usb_raw_ep0_read(fd, (struct usb_raw_ep_io*)&response); - debug("syz_usb_connect: read %d bytes\n", response.inner.length); - debug_dump_data(&event.data[0], response.inner.length); - } - if (rv < 0) { - debug("syz_usb_connect: usb_raw_ep0_read/write failed with %d\n", rv); - return rv; - } - } - - sleep_ms(200); - - debug("syz_usb_connect: configured\n"); - - 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 +#endif // SYZ_EXECUTOR || __NR_syz_usb_connect_ath9k #if SYZ_EXECUTOR || __NR_syz_usb_control_io + struct vusb_descriptor { uint8 req_type; uint8 desc_type; @@ -1134,167 +785,10 @@ static bool lookup_control_response(const struct vusb_descriptors* descs, const return false; } -static volatile long syz_usb_control_io(volatile long a0, volatile long a1, volatile long a2) -{ - int fd = a0; - 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; - event.inner.length = USB_MAX_PACKET_SIZE; - int rv = usb_raw_event_fetch(fd, (struct usb_raw_event*)&event); - if (rv < 0) { - debug("syz_usb_control_io: usb_raw_ep0_read failed with %d\n", rv); - return rv; - } - if (event.inner.type != USB_RAW_EVENT_CONTROL) { - debug("syz_usb_control_io: wrong event type: %d\n", (int)event.inner.type); - return -1; - } - - debug("syz_usb_control_io: bReqType: 0x%x (%s), bReq: 0x%x, wVal: 0x%x, wIdx: 0x%x, wLen: %d\n", - event.ctrl.bRequestType, (event.ctrl.bRequestType & USB_DIR_IN) ? "IN" : "OUT", - event.ctrl.bRequest, event.ctrl.wValue, event.ctrl.wIndex, event.ctrl.wLength); - -#if USB_DEBUG - 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) && event.ctrl.wLength) { - NONFAILING(response_found = lookup_control_response(descs, resps, &event.ctrl, &response_data, &response_length)); - if (!response_found) { - debug("syz_usb_control_io: unknown control IN request\n"); - return -1; - } - } else { - if ((event.ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD || - event.ctrl.bRequest == USB_REQ_SET_INTERFACE) { - int iface_num = event.ctrl.wIndex; - int alt_set = event.ctrl.wValue; - debug("syz_usb_control_io: setting interface (%d, %d)\n", iface_num, alt_set); - int iface_index = lookup_interface(fd, iface_num, alt_set); - if (iface_index < 0) { - debug("syz_usb_control_io: interface (%d, %d) not found\n", iface_num, alt_set); - } else { - set_interface(fd, iface_index); - debug("syz_usb_control_io: interface (%d, %d) set\n", iface_num, alt_set); - } - } - - response_length = event.ctrl.wLength; - } - - struct usb_raw_ep_io_data response; - response.inner.ep = 0; - response.inner.flags = 0; - if (response_length > sizeof(response.data)) - response_length = 0; - if (event.ctrl.wLength < response_length) - response_length = event.ctrl.wLength; - if ((event.ctrl.bRequestType & USB_DIR_IN) && !event.ctrl.wLength) { - // Something fishy is going on, try to read more data. - response_length = USB_MAX_PACKET_SIZE; - } - response.inner.length = response_length; - if (response_data) - memcpy(&response.data[0], response_data, response_length); - else - memset(&response.data[0], 0, response_length); - - if ((event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength) { - debug("syz_usb_control_io: writing %d bytes\n", response.inner.length); - debug_dump_data(&response.data[0], response.inner.length); - rv = usb_raw_ep0_write(fd, (struct usb_raw_ep_io*)&response); - } else { - rv = usb_raw_ep0_read(fd, (struct usb_raw_ep_io*)&response); - debug("syz_usb_control_io: read %d bytes\n", response.inner.length); - debug_dump_data(&response.data[0], response.inner.length); - } - if (rv < 0) { - debug("syz_usb_control_io: usb_raw_ep0_read/write failed with %d\n", rv); - return rv; - } +#endif // SYZ_EXECUTOR || __NR_syz_usb_control_io - sleep_ms(200); - - return 0; -} -#endif - -#if SYZ_EXECUTOR || __NR_syz_usb_ep_write -static volatile long syz_usb_ep_write(volatile long a0, volatile long a1, volatile long a2, volatile long a3) -{ - int fd = a0; - uint16 ep = a1; - uint32 len = a2; - char* data = (char*)a3; - - struct usb_raw_ep_io_data io_data; - io_data.inner.ep = ep; - io_data.inner.flags = 0; - if (len > sizeof(io_data.data)) - len = sizeof(io_data.data); - io_data.inner.length = len; - NONFAILING(memcpy(&io_data.data[0], data, len)); - - int rv = usb_raw_ep_write(fd, (struct usb_raw_ep_io*)&io_data); - if (rv < 0) { - debug("syz_usb_ep_write: usb_raw_ep_write failed with %d\n", rv); - return rv; - } - - sleep_ms(200); - - return 0; -} -#endif - -#if SYZ_EXECUTOR || __NR_syz_usb_ep_read -static volatile long syz_usb_ep_read(volatile long a0, volatile long a1, volatile long a2, volatile long a3) -{ - int fd = a0; - uint16 ep = a1; - uint32 len = a2; - char* data = (char*)a3; - - struct usb_raw_ep_io_data io_data; - io_data.inner.ep = ep; - io_data.inner.flags = 0; - if (len > sizeof(io_data.data)) - len = sizeof(io_data.data); - io_data.inner.length = len; - - int rv = usb_raw_ep_read(fd, (struct usb_raw_ep_io*)&io_data); - if (rv < 0) { - debug("syz_usb_ep_read: usb_raw_ep_read failed with %d\n", rv); - return rv; - } - - NONFAILING(memcpy(&data[0], &io_data.data[0], io_data.inner.length)); - - debug("syz_usb_ep_read: received data:\n"); - debug_dump_data(&io_data.data[0], io_data.inner.length); - - sleep_ms(200); - - return 0; -} -#endif - -#if SYZ_EXECUTOR || __NR_syz_usb_disconnect -static volatile long syz_usb_disconnect(volatile long a0) -{ - int fd = a0; - - int rv = close(fd); - - sleep_ms(200); - - return rv; -} -#endif +#if GOOS_linux +#include "common_usb_linux.h" +#else +#error "unknown OS" +#endif // GOOS_linux |
