From fa26c3cf35b4c8849e53da15351f1941aee227e1 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Tue, 18 Jun 2019 18:55:58 +0200 Subject: sys/linux, executor: add basic USB HID fuzzing support This commit adds the necessary descriptions and executor adjustments to enable targeted fuzzing of the enumeration process of USB HID devices. --- executor/common_usb.h | 103 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 73 insertions(+), 30 deletions(-) (limited to 'executor/common_usb.h') diff --git a/executor/common_usb.h b/executor/common_usb.h index 31071fd8c..8fe2b641b 100644 --- a/executor/common_usb.h +++ b/executor/common_usb.h @@ -139,6 +139,7 @@ int usb_fuzzer_vbus_draw(int fd, uint32 power) struct usb_fuzzer_control_event { struct usb_fuzzer_event inner; struct usb_ctrlrequest ctrl; + char data[USB_MAX_PACKET_SIZE]; }; struct usb_fuzzer_ep_io_data { @@ -180,8 +181,10 @@ static bool lookup_connect_response(struct vusb_connect_descriptors* descs, stru return true; case USB_DT_STRING: str_idx = (uint8)ctrl->wValue; - if (str_idx >= descs->strs_len) - return false; + if (str_idx >= descs->strs_len && descs->strs_len > 0) { + // Use the last string if we ran out. + str_idx = descs->strs_len - 1; + } *response_data = descs->strs[str_idx].str; *response_length = descs->strs[str_idx].len; return true; @@ -232,27 +235,35 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatil struct usb_device_index index; memset(&index, 0, sizeof(index)); - int rv = false; + int rv = 0; NONFAILING(rv = parse_usb_descriptor(dev, dev_len, &index)); - if (!rv) - return -1; + if (!rv) { + debug("syz_usb_connect: parse_usb_descriptor failed with %d\n", rv); + return rv; + } debug("syz_usb_connect: parsed usb descriptor\n"); int fd = usb_fuzzer_open(); - if (fd < 0) - return -1; + if (fd < 0) { + debug("syz_usb_connect: usb_fuzzer_open failed with %d\n", rv); + return fd; + } debug("syz_usb_connect: usb_fuzzer_open success\n"); char device[32]; sprintf(&device[0], "dummy_udc.%llu", procid); rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]); - if (rv < 0) - return -1; + if (rv < 0) { + debug("syz_usb_connect: usb_fuzzer_init failed with %d\n", rv); + return rv; + } debug("syz_usb_connect: usb_fuzzer_init success\n"); rv = usb_fuzzer_run(fd); - if (rv < 0) - return -1; + if (rv < 0) { + debug("syz_usb_connect: usb_fuzzer_run failed with %d\n", rv); + return rv; + } debug("syz_usb_connect: usb_fuzzer_run success\n"); bool done = false; @@ -261,28 +272,37 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatil event.inner.type = 0; event.inner.length = sizeof(event.ctrl); rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event); - if (rv < 0) - return -1; + if (rv < 0) { + debug("syz_usb_connect: usb_fuzzer_ep0_read failed with %d\n", rv); + return rv; + } if (event.inner.type != USB_FUZZER_EVENT_CONTROL) continue; - debug("syz_usb_connect: bRequestType: 0x%x, bRequest: 0x%x, wValue: 0x%x, wIndex: 0x%x, wLength: %d\n", - event.ctrl.bRequestType, event.ctrl.bRequest, event.ctrl.wValue, event.ctrl.wIndex, event.ctrl.wLength); + debug("syz_usb_connect: bRequestType: 0x%x (%s), bRequest: 0x%x, wValue: 0x%x, wIndex: 0x%x, wLength: %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); bool response_found = false; char* response_data = NULL; uint32 response_length = 0; NONFAILING(response_found = lookup_connect_response(descs, &index, &event.ctrl, &response_data, &response_length, &done)); - if (!response_found) + if (!response_found) { + debug("syz_usb_connect: no response found\n"); return -1; + } if (done) { - int rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower); - if (rv < 0) - return -1; + rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower); + if (rv < 0) { + debug("syz_usb_connect: usb_fuzzer_vbus_draw failed with %d\n", rv); + return rv; + } rv = usb_fuzzer_configure(fd); - if (rv < 0) - return -1; + if (rv < 0) { + debug("syz_usb_connect: usb_fuzzer_configure failed with %d\n", rv); + return rv; + } unsigned ep; for (ep = 0; ep < index.eps_num; ep++) { rv = usb_fuzzer_ep_enable(fd, index.eps[ep]); @@ -302,7 +322,11 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatil if (event.ctrl.wLength < response.inner.length) response.inner.length = event.ctrl.wLength; debug("syz_usb_connect: reply length = %d\n", response.inner.length); - usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response); + rv = usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response); + if (rv < 0) { + debug("syz_usb_connect: usb_fuzzer_ep0_write failed with %d\n", rv); + return rv; + } } sleep_ms(200); @@ -406,22 +430,34 @@ static volatile long syz_usb_control_io(volatile long a0, volatile long a1, vola struct usb_fuzzer_control_event event; event.inner.type = 0; - event.inner.length = sizeof(event.ctrl); + event.inner.length = USB_MAX_PACKET_SIZE; int rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event); - if (rv < 0) - return -1; - if (event.inner.type != USB_FUZZER_EVENT_CONTROL) + if (rv < 0) { + debug("syz_usb_control_io: usb_fuzzer_ep0_read failed with %d\n", rv); + return rv; + } + if (event.inner.type != USB_FUZZER_EVENT_CONTROL) { + debug("syz_usb_control_io: wrong event type: %d\n", (int)event.inner.type); return -1; + } - debug("syz_usb_control_io: bRequestType: 0x%x, bRequest: 0x%x, wValue: 0x%x, wIndex: 0x%x, wLength: %d\n", - event.ctrl.bRequestType, event.ctrl.bRequest, event.ctrl.wValue, event.ctrl.wIndex, event.ctrl.wLength); + debug("syz_usb_control_io: bRequestType: 0x%x (%s), bRequest: 0x%x, wValue: 0x%x, wIndex: 0x%x, wLength: %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 (!(event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength != 0) { + debug("syz_usb_control_io: OUT data:\n"); + debug_dump_data(&event.data[0], event.ctrl.wLength); + } bool response_found = false; char* response_data = NULL; uint32 response_length = 0; NONFAILING(response_found = lookup_control_io_response(descs, resps, &event.ctrl, &response_data, &response_length)); - if (!response_found) + if (!response_found) { + debug("syz_usb_control_io: no response found\n"); return -1; + } struct usb_fuzzer_ep_io_data response; response.inner.ep = 0; @@ -434,7 +470,14 @@ static volatile long syz_usb_control_io(volatile long a0, volatile long a1, vola if (event.ctrl.wLength < response.inner.length) response.inner.length = event.ctrl.wLength; debug("syz_usb_control_io: response length = %d\n", response.inner.length); - usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response); + debug_dump_data(&response.data[0], response.inner.length); + rv = usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response); + if (rv < 0) { + debug("syz_usb_control_io: usb_fuzzer_ep0_write failed with %d\n", rv); + return rv; + } + + sleep_ms(200); return 0; } -- cgit mrf-deployment