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. --- sys/linux/vusb.txt | 258 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 156 insertions(+), 102 deletions(-) (limited to 'sys/linux') diff --git a/sys/linux/vusb.txt b/sys/linux/vusb.txt index 5e9177cd6..4eb8040ee 100644 --- a/sys/linux/vusb.txt +++ b/sys/linux/vusb.txt @@ -13,29 +13,34 @@ include # This is a special fd for USB fuzzing and should only be used with syz_usb_* syzcalls. # We don't inherit it from the fd resource, to discourage syzkaller calling raw ioctls on it. resource fd_usb[int32]: -1 +resource fd_usb_hid[fd_usb] +# These are generic syzcalls for emulating arbitrary USB devices. +# They are mostly targeted to cover the enumeration process. syz_usb_connect(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb syz_usb_control_io(fd fd_usb, descs ptr[in, vusb_descriptors], resps ptr[in, vusb_responses]) syz_usb_ep_write(fd fd_usb, ep int16[0:31], len len[data], data buffer[in]) syz_usb_disconnect(fd fd_usb) +# These are syzcalls specifically targeted to the HID device class. +syz_usb_connect$hid(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_hid], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_hid +syz_usb_control_io$hid(fd fd_usb_hid, descs ptr[in, vusb_descriptors_hid], resps ptr[in, vusb_responses_hid]) + usb_device_speed = USB_SPEED_UNKNOWN, USB_SPEED_LOW, USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_WIRELESS, USB_SPEED_SUPER, USB_SPEED_SUPER_PLUS # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# USB device, configuration, interface and endpoint descriptors. - type usb_device_descriptor_t[CLASS, SUBCLASS, PROTOCOL, VENDOR, PRODUCT, DEVICE, CFS] { bLength const[USB_DT_DEVICE_SIZE, int8] bDescriptorType const[USB_DT_DEVICE, int8] - bcdUSB int16 + bcdUSB flags[usb_versions, int16] bDeviceClass const[CLASS, int8] bDeviceSubClass const[SUBCLASS, int8] bDeviceProtocol const[PROTOCOL, int8] - bMaxPacketSize0 int8 + bMaxPacketSize0 flags[usb_max_packet_sizes, int8] idVendor const[VENDOR, int16] idProduct const[PRODUCT, int16] bcdDevice const[DEVICE, int16] @@ -47,14 +52,12 @@ type usb_device_descriptor_t[CLASS, SUBCLASS, PROTOCOL, VENDOR, PRODUCT, DEVICE, configs CFS } [packed] -# TODO: support more than one configuration. -# bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct -# and bcdDevice are patched by Go code, see sys/linux/init_vusb.go. -usb_device_descriptor { - inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]] -} [packed] +usb_versions = 0x110, 0x200, 0x201, 0x250, 0x300, 0x310 + +# https://elixir.bootlin.com/linux/v5.1.7/source/drivers/usb/core/hub.c#L4661 +usb_max_packet_sizes = 8, 16, 32, 64 -type usb_config_descriptor_t[IFS] { +type usb_config_descriptor_t[ATTRS, IFS] { bLength const[USB_DT_CONFIG_SIZE, int8] bDescriptorType const[USB_DT_CONFIG, int8] @@ -62,19 +65,12 @@ type usb_config_descriptor_t[IFS] { bNumInterfaces len[interfaces, int8] bConfigurationValue int8 iConfiguration int8 - bmAttributes flags[usb_config_attributes, int8] + bmAttributes ATTRS bMaxPower int8 interfaces IFS } [packed] -# TODO: support more than one interface. -usb_config_descriptor { - inner usb_config_descriptor_t[array[usb_interface_descriptor, 1]] -} [packed] - -usb_config_attributes = USB_CONFIG_ATT_ONE, USB_CONFIG_ATT_SELFPOWER, USB_CONFIG_ATT_WAKEUP, USB_CONFIG_ATT_BATTERY - type usb_interface_descriptor_t[CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] { bLength const[USB_DT_INTERFACE_SIZE, int8] bDescriptorType const[USB_DT_INTERFACE, int8] @@ -91,18 +87,12 @@ type usb_interface_descriptor_t[CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] { endpoints EPS } [packed] -# bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol -# are patched by Go code, see sys/linux/init_vusb.go. -usb_interface_descriptor { - inner usb_interface_descriptor_t[0, 0, 0, array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]] -} [packed] - -type usb_endpoint_descriptor_t[EXTRA] { +type usb_endpoint_descriptor_t[ADDR, ATTRS, EXTRA] { bLength const[USB_DT_ENDPOINT_SIZE, int8] bDescriptorType const[USB_DT_ENDPOINT, int8] - bEndpointAddress int8 - bmAttributes flags[usb_endpoint_attributes, int8] + bEndpointAddress ADDR + bmAttributes ATTRS wMaxPacketSize int16 bInterval int8 bRefresh int8 @@ -111,17 +101,39 @@ type usb_endpoint_descriptor_t[EXTRA] { extra EXTRA } [packed] -usb_endpoint_descriptor { - inner usb_endpoint_descriptor_t[array[usb_endpoint_extra_descriptor, 0:2]] -} [packed] - -usb_endpoint_attributes = USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_INT, USB_ENDPOINT_INTR_PERIODIC, USB_ENDPOINT_INTR_NOTIFICATION, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC, USB_ENDPOINT_USAGE_DATA, USB_ENDPOINT_USAGE_FEEDBACK, USB_ENDPOINT_USAGE_FEEDBACK - # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# USB descriptors requested by the kernel before the SET_CONFIGURATION request. +# Generic USB device, configuration, interface and endpoint descriptors. + +# TODO: support more than one configuration. +# bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct +# and bcdDevice are patched by Go code, see sys/linux/init_vusb.go. +usb_device_descriptor { + inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]] +} [packed] + +# TODO: support more than one interface. +usb_config_descriptor { + inner usb_config_descriptor_t[flags[usb_config_attributes, int8], array[usb_interface_descriptor, 1]] +} [packed] + +usb_config_attributes = USB_CONFIG_ATT_ONE, USB_CONFIG_ATT_SELFPOWER, USB_CONFIG_ATT_WAKEUP, USB_CONFIG_ATT_BATTERY + +# bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol +# are patched by Go code, see sys/linux/init_vusb.go. +usb_interface_descriptor { + inner usb_interface_descriptor_t[0, 0, 0, array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]] +} [packed] + +usb_endpoint_descriptor { + inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], array[usb_endpoint_extra_descriptor, 0:2]] +} [packed] + +usb_endpoint_addresses = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, USB_DIR_OUT, USB_DIR_IN + +usb_endpoint_attributes = USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_INT, USB_ENDPOINT_INTR_PERIODIC, USB_ENDPOINT_INTR_NOTIFICATION, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC, USB_ENDPOINT_USAGE_DATA, USB_ENDPOINT_USAGE_FEEDBACK, USB_ENDPOINT_USAGE_FEEDBACK # TODO: consider unifying with vusb_descriptors in case this struct significantly grows. vusb_connect_descriptors { @@ -138,6 +150,113 @@ vusb_connect_string_descriptor { str ptr[in, usb_string_descriptor] } [packed] +vusb_descriptors { + len len[parent, int32] + generic ptr[in, vusb_descriptor_generic] + string ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]] + hid_report ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_REPORT, hid_descriptor_report]] + bos ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_BOS, usb_bos_descriptor]] + hub_hs ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_HUB, usb_hub_descriptor_hs]] + hub_ss ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_SS_HUB, usb_hub_descriptor_ss]] +} [packed] + +vusb_descriptor_generic { + req_type flags[usb_request_types, int8] + desc_type flags[usb_descriptor_types, int8] + len bytesize[data, int32] + data usb_generic_descriptor +} [packed] + +usb_request_types = USB_TYPE_STANDARD, USB_TYPE_CLASS, USB_TYPE_VENDOR + +type vusb_descriptor_t[CLASS, REQ, DATA] { + type const[CLASS, int8] + req const[REQ, int8] + len bytesize[data, int32] + data DATA +} [packed] + +vusb_responses { + len len[parent, int32] + generic ptr[in, vusb_response_generic] + set_interface ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_SET_INTERFACE, void]] + get_interface ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_INTERFACE, int8]] + set_configuration ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_SET_CONFIGURATION, void]] + get_configuration ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_CONFIGURATION, int8]] + get_status_hub ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_hub_status]] + get_status_port ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_port_status]] + aiptek_get_report ptr[in, vusb_response_t[USB_TYPE_VENDOR, 0x1, array[int8, 3]]] + aiptek_set_report ptr[in, vusb_response_t[USB_TYPE_VENDOR, 0x9, array[int8, 3]]] + cdc_get_ntb_parameters ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_PARAMETERS, usb_cdc_ncm_ntb_parameters]] +} [packed] + +vusb_response_generic { + type flags[usb_request_types, int8] + req flags[usb_requests, int8] + len bytesize[data, int32] + data array[int8] +} [packed] + +usb_requests = USB_REQ_GET_STATUS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE, USB_REQ_SET_ADDRESS, USB_REQ_GET_DESCRIPTOR, USB_REQ_SET_DESCRIPTOR, USB_REQ_GET_CONFIGURATION, USB_REQ_SET_CONFIGURATION, USB_REQ_GET_INTERFACE, USB_REQ_SET_INTERFACE, USB_REQ_SYNCH_FRAME, USB_REQ_SET_SEL, USB_REQ_SET_ISOCH_DELAY, USB_REQ_SET_ENCRYPTION, USB_REQ_GET_ENCRYPTION, USB_REQ_RPIPE_ABORT, USB_REQ_SET_HANDSHAKE, USB_REQ_RPIPE_RESET, USB_REQ_GET_HANDSHAKE, USB_REQ_SET_CONNECTION, USB_REQ_SET_SECURITY_DATA, USB_REQ_GET_SECURITY_DATA, USB_REQ_SET_WUSB_DATA, USB_REQ_LOOPBACK_DATA_WRITE, USB_REQ_LOOPBACK_DATA_READ, USB_REQ_SET_INTERFACE_DS, USB_REQ_GET_PARTNER_PDO, USB_REQ_GET_BATTERY_STATUS, USB_REQ_SET_PDO, USB_REQ_GET_VDM, USB_REQ_SEND_VDM + +type vusb_response_t[CLASS, REQ, DATA] { + type const[CLASS, int8] + req const[REQ, int8] + len bytesize[data, int32] + data DATA +} [packed] + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +# USB device, configuration, interface and endpoint descriptors for the HID device class. +# Modelled after the Logitech K120 keyboard. + +usb_device_descriptor_hid { + inner usb_device_descriptor_t[0, 0, 0, 0x46d, 0xc31c, 64, array[usb_config_descriptor_hid, 1]] +} [packed] + +usb_config_descriptor_hid { + inner usb_config_descriptor_t[const[USB_CONFIG_HID_ATTRIBUTES, int8], array[usb_interface_descriptor_hid, 1]] +} [packed] + +usb_interface_descriptor_hid { + inner usb_interface_descriptor_t[USB_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_KEYBOARD, hid_descriptor_hid, array[usb_endpoint_descriptor_hid, 1]] +} [packed] + +usb_endpoint_descriptor_hid { + inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], array[usb_endpoint_extra_descriptor, 0:2]] +} [packed] + +define USB_CONFIG_HID_ATTRIBUTES (USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_WAKEUP) +define USB_ENDPOINT_HID_ADDRESS (1 | USB_DIR_IN) +define USB_ENDPOINT_HID_ATTRIBUTES (USB_ENDPOINT_XFER_INT) + +# TODO: consider merging with vusb_descriptors. +vusb_descriptors_hid { + len len[parent, int32] + generic ptr[in, vusb_descriptor_generic] + string ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]] + hid_report ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_REPORT, hid_descriptor_report]] + bos ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_BOS, usb_bos_descriptor]] +} [packed] + +# TODO: consider merging with vusb_responses. +vusb_responses_hid { + len len[parent, int32] + generic ptr[in, vusb_response_generic] + set_idle ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_SET_IDLE, void]] + set_report ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_SET_REPORT, void]] + set_protocol ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_SET_PROTOCOL, void]] +} [packed] + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +# USB descriptors requested by the kernel before the SET_CONFIGURATION request. + usb_string_descriptor { bLength len[parent, int8] bDescriptorType const[USB_DT_STRING, int8] @@ -152,11 +271,11 @@ usb_qualifier_descriptor { bLength len[parent, int8] bDescriptorType const[USB_DT_DEVICE_QUALIFIER, int8] - bcdUSB int16 + bcdUSB flags[usb_versions, int16] bDeviceClass int8 bDeviceSubClass int8 bDeviceProtocol int8 - bMaxPacketSize0 int8 + bMaxPacketSize0 flags[usb_max_packet_sizes, int8] bNumConfigurations int8 bRESERVED const[0, int8] } [packed] @@ -505,7 +624,6 @@ usb_cdc_mbim_extended_desc { # USB descriptors requested after the SET_CONFIGURATION request. # TODO: define recusively to generate proper structures. - hid_descriptor_report { items array[hid_report_item] } [packed] @@ -623,67 +741,3 @@ usb_cdc_ncm_ntb_parameters { # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - -vusb_descriptors { - len len[parent, int32] - generic ptr[in, vusb_descriptor_generic] - string ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]] - hid_report ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_REPORT, hid_descriptor_report]] - bos ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_BOS, usb_bos_descriptor]] - hub_hs ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_HUB, usb_hub_descriptor_hs]] - hub_ss ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_SS_HUB, usb_hub_descriptor_ss]] -} [packed] - -vusb_descriptor_generic { - req_type flags[usb_request_types, int8] - desc_type flags[usb_descriptor_types, int8] - len bytesize[data, int32] - data usb_generic_descriptor -} [packed] - -usb_request_types = USB_TYPE_STANDARD, USB_TYPE_CLASS, USB_TYPE_VENDOR - -type vusb_descriptor_t[CLASS, REQ, DATA] { - type const[CLASS, int8] - req const[REQ, int8] - len bytesize[data, int32] - data DATA -} [packed] - -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - -vusb_responses { - len len[parent, int32] - generic ptr[in, vusb_response_generic] - set_interface ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_SET_INTERFACE, void]] - get_interface ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_INTERFACE, int8]] - set_configuration ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_SET_CONFIGURATION, void]] - get_configuration ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_CONFIGURATION, int8]] - get_status_hub ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_hub_status]] - get_status_port ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_port_status]] - aiptek_get_report ptr[in, vusb_response_t[USB_TYPE_VENDOR, 0x1, array[int8, 3]]] - aiptek_set_report ptr[in, vusb_response_t[USB_TYPE_VENDOR, 0x9, array[int8, 3]]] - cdc_get_ntb_parameters ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_PARAMETERS, usb_cdc_ncm_ntb_parameters]] -} [packed] - -vusb_response_generic { - type flags[usb_request_types, int8] - req flags[usb_requests, int8] - len bytesize[data, int32] - data array[int8] -} [packed] - -usb_requests = USB_REQ_GET_STATUS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE, USB_REQ_SET_ADDRESS, USB_REQ_GET_DESCRIPTOR, USB_REQ_SET_DESCRIPTOR, USB_REQ_GET_CONFIGURATION, USB_REQ_SET_CONFIGURATION, USB_REQ_GET_INTERFACE, USB_REQ_SET_INTERFACE, USB_REQ_SYNCH_FRAME, USB_REQ_SET_SEL, USB_REQ_SET_ISOCH_DELAY, USB_REQ_SET_ENCRYPTION, USB_REQ_GET_ENCRYPTION, USB_REQ_RPIPE_ABORT, USB_REQ_SET_HANDSHAKE, USB_REQ_RPIPE_RESET, USB_REQ_GET_HANDSHAKE, USB_REQ_SET_CONNECTION, USB_REQ_SET_SECURITY_DATA, USB_REQ_GET_SECURITY_DATA, USB_REQ_SET_WUSB_DATA, USB_REQ_LOOPBACK_DATA_WRITE, USB_REQ_LOOPBACK_DATA_READ, USB_REQ_SET_INTERFACE_DS, USB_REQ_GET_PARTNER_PDO, USB_REQ_GET_BATTERY_STATUS, USB_REQ_SET_PDO, USB_REQ_GET_VDM, USB_REQ_SEND_VDM - -type vusb_response_t[CLASS, REQ, DATA] { - type const[CLASS, int8] - req const[REQ, int8] - len bytesize[data, int32] - data DATA -} [packed] - -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -- cgit mrf-deployment