Skip to contentSkip to conversation

usb: gadget: add raw-gadget interface

PATCH In review Andrey Konovalov 2 participants 5 messages Feb 24, 2020 – Mar 12, 2020

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v6 cover usb: gadget: add raw-gadget interface

This patchset (currently a single patch) adds a new userspace interface for the USB Gadget subsystem called USB Raw Gadget. This is what is currently being used to enable coverage-guided USB fuzzing with syzkaller:

https://github.com/google/syzkaller/blob/master/docs/linux/external_fuzzing_usb.md

Initially I was using GadgetFS (together with the Dummy HCD/UDC module) to perform emulation of USB devices for fuzzing, but later switched to a custom written interface. The incentive to implement a different interface was to provide a somewhat raw and direct access to the USB Gadget layer for the userspace, where every USB request is passed to the userspace to get a response. See documentation for the list of differences between Raw Gadget and GadgetFS.

Currently Raw Gadget only supports blocking I/O mode, that synchronously waits for the result of each operation to allow collecting coverage per operation.

This patchset has been pushed to the public Linux kernel Gerrit instance:

https://linux-review.googlesource.com/c/linux/kernel/git/torvalds/linux/+/2144

Changes v5 -> v6:
- Prevent raw_process_ep_io() racing with raw_ioctl_ep_disable() by checking urb_queued flag in the latter.
- Use GFP_KERNEL instead of GFP_ATOMIC where possible.
- Reject opening raw-gadget with O_NONBLOCK to allow future extensions to support nonblocking IO.
- Reduce RAW_EVENT_QUEUE_SIZE to 16.

Changes v4 -> v5:
- Specified explicit usb_raw_event_type enum values for all entries.
- Dropped pointless locking in gadget_unbind().

Changes v3 -> v4:
- Print debug message when maxpacket check fails.
- Use module_misc_device() instead of module_init/exit().
- Reuse DRIVER_NAME macro in raw_device struct definition.
- Don't print WARNING in raw_release().
- Add comment that explains locking into raw_event_queue_fetch().
- Print a WARNING when event queue size is exceeded.
- Rename raw.c to raw_gadget.c.
- Mention module name in Kconfig.
- Reworked logging to use dev_err/dbg() instead of pr_err/debug().

Changes v2 -> v3:
- Updated device path in documentation.
- Changed usb_raw_init struct layout to make it the same for 32 bit compat mode.
- Added compat_ioctl to raw_fops.
- Changed raw_ioctl_init() to return EINVAL for invalid USB speeds, except for USB_SPEED_UNKNOWN, which defaults to USB_SPEED_HIGH.
- Reject endpoints with maxpacket = 0 in raw_ioctl_ep_enable().

Changes v1 -> v2:
- Moved raw.c to legacy/.
- Changed uapi header to use __u* types.
- Switched from debugfs entry to a misc device.
- Changed raw_dev from refcount to kref.
- Moved UDC_NAME_LENGTH_MAX to uapi headers.
- Used usb_endpoint_type() and usb_endpoint_dir_in/out() functions instead of open coding them.
- Added "WITH Linux-syscall-note" to SPDX id in the uapi header.
- Removed pr_err() if case dev_new() fails.
- Reduced the number of debugging messages.

Andrey Konovalov (1):
usb: gadget: add raw-gadget interface

 Documentation/usb/index.rst            |    1 +
 Documentation/usb/raw-gadget.rst       |   61 ++
 drivers/usb/gadget/legacy/Kconfig      |   11 +
 drivers/usb/gadget/legacy/Makefile     |    1 +
 drivers/usb/gadget/legacy/raw_gadget.c | 1078 ++++++++++++++++++++++++
 include/uapi/linux/usb/raw_gadget.h    |  167 ++++
 6 files changed, 1319 insertions(+)
 create mode 100644 Documentation/usb/raw-gadget.rst
 create mode 100644 drivers/usb/gadget/legacy/raw_gadget.c
 create mode 100644 include/uapi/linux/usb/raw_gadget.h
Signature · 1 line
2.25.0.265.gbab2e86ba0-goog
#1 lore raw

PATCH v6 1/1 usb: gadget: add raw-gadget interface

USB Raw Gadget is a kernel module that provides a userspace interface for the USB Gadget subsystem. Essentially it allows to emulate USB devices from userspace. Enabled with CONFIG_USB_RAW_GADGET. Raw Gadget is currently a strictly debugging feature and shouldn't be used in production.

Raw Gadget is similar to GadgetFS, but provides a more low-level and direct access to the USB Gadget layer for the userspace. The key differences are:

1. Every USB request is passed to the userspace to get a response, while GadgetFS responds to some USB requests internally based on the provided descriptors. However note, that the UDC driver might respond to some requests on its own and never forward them to the Gadget layer.

2. GadgetFS performs some sanity checks on the provided USB descriptors, while Raw Gadget allows you to provide arbitrary data as responses to USB requests.

3. Raw Gadget provides a way to select a UDC device/driver to bind to, while GadgetFS currently binds to the first available UDC.

4. Raw Gadget uses predictable endpoint names (handles) across different UDCs (as long as UDCs have enough endpoints of each required transfer type).

5. Raw Gadget has ioctl-based interface instead of a filesystem-based one.

---
 Documentation/usb/index.rst            |    1 +
 Documentation/usb/raw-gadget.rst       |   61 ++
 drivers/usb/gadget/legacy/Kconfig      |   11 +
 drivers/usb/gadget/legacy/Makefile     |    1 +
 drivers/usb/gadget/legacy/raw_gadget.c | 1078 ++++++++++++++++++++++++
 include/uapi/linux/usb/raw_gadget.h    |  167 ++++
 6 files changed, 1319 insertions(+)
 create mode 100644 Documentation/usb/raw-gadget.rst
 create mode 100644 drivers/usb/gadget/legacy/raw_gadget.c
 create mode 100644 include/uapi/linux/usb/raw_gadget.h
Documentation/usb/index.rst +1 -0
index 36b6ebd9a9d9..b656c9be23ed 100644
@@ -22,6 +22,7 @@ USB support
     misc_usbsevseg
     mtouchusb
     ohci
+    raw-gadget
     usbip_protocol
     usbmon
     usb-serial
Documentation/usb/raw-gadget.rst new file +61 -0

61 lines not on this page · raw message

drivers/usb/gadget/legacy/Kconfig +11 -0
index 6e7e1a9202e6..a7064e21d9f2 100644
@@ -516,4 +516,15 @@ config USB_G_WEBCAM
 	  Say "y" to link the driver statically, or "m" to build a
 	  dynamically linked module called "g_webcam".
 
+config USB_RAW_GADGET
+	tristate "USB Raw Gadget"
+	help
+	  USB Raw Gadget is a kernel module that provides a userspace interface
+	  for the USB Gadget subsystem. Essentially it allows to emulate USB
+	  devices from userspace. See Documentation/usb/raw-gadget.rst for
+	  details.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "raw_gadget".
+
 endchoice
drivers/usb/gadget/legacy/Makefile +1 -0
index abd0c3e66a05..4d864bf82799 100644
@@ -43,3 +43,4 @@ obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
 obj-$(CONFIG_USB_G_NCM)		+= g_ncm.o
 obj-$(CONFIG_USB_G_ACM_MS)	+= g_acm_ms.o
 obj-$(CONFIG_USB_GADGET_TARGET)	+= tcm_usb_gadget.o
+obj-$(CONFIG_USB_RAW_GADGET)	+= raw_gadget.o
drivers/usb/gadget/legacy/raw_gadget.c new file +1078 -0

1,078 lines not on this page · raw message

include/uapi/linux/usb/raw_gadget.h new file +167 -0

167 lines not on this page · raw message

Signature · 1 line
2.25.0.265.gbab2e86ba0-goog
#2 lore raw
In reply to Andrey Konovalov
Quoted 23 lines · Andrey Konovalov

This patchset (currently a single patch) adds a new userspace interface for the USB Gadget subsystem called USB Raw Gadget. This is what is currently being used to enable coverage-guided USB fuzzing with syzkaller:

https://github.com/google/syzkaller/blob/master/docs/linux/external_fuzzing_usb.md

Initially I was using GadgetFS (together with the Dummy HCD/UDC module) to perform emulation of USB devices for fuzzing, but later switched to a custom written interface. The incentive to implement a different interface was to provide a somewhat raw and direct access to the USB Gadget layer for the userspace, where every USB request is passed to the userspace to get a response. See documentation for the list of differences between Raw Gadget and GadgetFS.

Currently Raw Gadget only supports blocking I/O mode, that synchronously waits for the result of each operation to allow collecting coverage per operation.

This patchset has been pushed to the public Linux kernel Gerrit instance:

https://linux-review.googlesource.com/c/linux/kernel/git/torvalds/linux/+/2144

Quoted 7 lines

Changes v5 -> v6:
- Prevent raw_process_ep_io() racing with raw_ioctl_ep_disable() by checking urb_queued flag in the latter.
- Use GFP_KERNEL instead of GFP_ATOMIC where possible.
- Reject opening raw-gadget with O_NONBLOCK to allow future extensions to support nonblocking IO.
- Reduce RAW_EVENT_QUEUE_SIZE to 16.

Hi Felipe! I'm still hoping for a review :)

(Forgot to add a link to the example that emulates a USB keyboard via Raw Gadget into the cover letter:

https://github.com/xairy/raw-gadget/blob/master/examples/keyboard.c)

Quoted 54 lines

Changes v4 -> v5:
- Specified explicit usb_raw_event_type enum values for all entries.
- Dropped pointless locking in gadget_unbind().

Changes v3 -> v4:
- Print debug message when maxpacket check fails.
- Use module_misc_device() instead of module_init/exit().
- Reuse DRIVER_NAME macro in raw_device struct definition.
- Don't print WARNING in raw_release().
- Add comment that explains locking into raw_event_queue_fetch().
- Print a WARNING when event queue size is exceeded.
- Rename raw.c to raw_gadget.c.
- Mention module name in Kconfig.
- Reworked logging to use dev_err/dbg() instead of pr_err/debug().

Changes v2 -> v3:
- Updated device path in documentation.
- Changed usb_raw_init struct layout to make it the same for 32 bit compat mode.
- Added compat_ioctl to raw_fops.
- Changed raw_ioctl_init() to return EINVAL for invalid USB speeds, except for USB_SPEED_UNKNOWN, which defaults to USB_SPEED_HIGH.
- Reject endpoints with maxpacket = 0 in raw_ioctl_ep_enable().

Changes v1 -> v2:
- Moved raw.c to legacy/.
- Changed uapi header to use __u* types.
- Switched from debugfs entry to a misc device.
- Changed raw_dev from refcount to kref.
- Moved UDC_NAME_LENGTH_MAX to uapi headers.
- Used usb_endpoint_type() and usb_endpoint_dir_in/out() functions instead of open coding them.
- Added "WITH Linux-syscall-note" to SPDX id in the uapi header.
- Removed pr_err() if case dev_new() fails.
- Reduced the number of debugging messages.

Andrey Konovalov (1):
usb: gadget: add raw-gadget interface

 Documentation/usb/index.rst            |    1 +
 Documentation/usb/raw-gadget.rst       |   61 ++
 drivers/usb/gadget/legacy/Kconfig      |   11 +
 drivers/usb/gadget/legacy/Makefile     |    1 +
 drivers/usb/gadget/legacy/raw_gadget.c | 1078 ++++++++++++++++++++++++
 include/uapi/linux/usb/raw_gadget.h    |  167 ++++
 6 files changed, 1319 insertions(+)
 create mode 100644 Documentation/usb/raw-gadget.rst
 create mode 100644 drivers/usb/gadget/legacy/raw_gadget.c
 create mode 100644 include/uapi/linux/usb/raw_gadget.h

--
2.25.0.265.gbab2e86ba0-goog

#3 lore raw
Quoted 33 lines · Andrey Konovalov
Quoted 23 lines · Andrey Konovalov

This patchset (currently a single patch) adds a new userspace interface for the USB Gadget subsystem called USB Raw Gadget. This is what is currently being used to enable coverage-guided USB fuzzing with syzkaller:

https://github.com/google/syzkaller/blob/master/docs/linux/external_fuzzing_usb.md

Initially I was using GadgetFS (together with the Dummy HCD/UDC module) to perform emulation of USB devices for fuzzing, but later switched to a custom written interface. The incentive to implement a different interface was to provide a somewhat raw and direct access to the USB Gadget layer for the userspace, where every USB request is passed to the userspace to get a response. See documentation for the list of differences between Raw Gadget and GadgetFS.

Currently Raw Gadget only supports blocking I/O mode, that synchronously waits for the result of each operation to allow collecting coverage per operation.

This patchset has been pushed to the public Linux kernel Gerrit instance:

https://linux-review.googlesource.com/c/linux/kernel/git/torvalds/linux/+/2144

Quoted 7 lines

Changes v5 -> v6:
- Prevent raw_process_ep_io() racing with raw_ioctl_ep_disable() by checking urb_queued flag in the latter.
- Use GFP_KERNEL instead of GFP_ATOMIC where possible.
- Reject opening raw-gadget with O_NONBLOCK to allow future extensions to support nonblocking IO.
- Reduce RAW_EVENT_QUEUE_SIZE to 16.

Quoted 6 lines

Hi Felipe! I'm still hoping for a review :)

(Forgot to add a link to the example that emulates a USB keyboard via Raw Gadget into the cover letter:

https://github.com/xairy/raw-gadget/blob/master/examples/keyboard.c)

Hi Greg, Felipe, and Alan,

I was wondering if there's a way to move forward with this patch?

Alan, since you have a very good knowledge of the USB subsystem, could I ask you to take a look at the patch, while Felipe is busy?

Thanks!

Quoted 55 lines
Quoted 55 lines

Changes v4 -> v5:
- Specified explicit usb_raw_event_type enum values for all entries.
- Dropped pointless locking in gadget_unbind().

Changes v3 -> v4:
- Print debug message when maxpacket check fails.
- Use module_misc_device() instead of module_init/exit().
- Reuse DRIVER_NAME macro in raw_device struct definition.
- Don't print WARNING in raw_release().
- Add comment that explains locking into raw_event_queue_fetch().
- Print a WARNING when event queue size is exceeded.
- Rename raw.c to raw_gadget.c.
- Mention module name in Kconfig.
- Reworked logging to use dev_err/dbg() instead of pr_err/debug().

Changes v2 -> v3:
- Updated device path in documentation.
- Changed usb_raw_init struct layout to make it the same for 32 bit compat mode.
- Added compat_ioctl to raw_fops.
- Changed raw_ioctl_init() to return EINVAL for invalid USB speeds, except for USB_SPEED_UNKNOWN, which defaults to USB_SPEED_HIGH.
- Reject endpoints with maxpacket = 0 in raw_ioctl_ep_enable().

Changes v1 -> v2:
- Moved raw.c to legacy/.
- Changed uapi header to use __u* types.
- Switched from debugfs entry to a misc device.
- Changed raw_dev from refcount to kref.
- Moved UDC_NAME_LENGTH_MAX to uapi headers.
- Used usb_endpoint_type() and usb_endpoint_dir_in/out() functions instead of open coding them.
- Added "WITH Linux-syscall-note" to SPDX id in the uapi header.
- Removed pr_err() if case dev_new() fails.
- Reduced the number of debugging messages.

Andrey Konovalov (1):
usb: gadget: add raw-gadget interface

 Documentation/usb/index.rst            |    1 +
 Documentation/usb/raw-gadget.rst       |   61 ++
 drivers/usb/gadget/legacy/Kconfig      |   11 +
 drivers/usb/gadget/legacy/Makefile     |    1 +
 drivers/usb/gadget/legacy/raw_gadget.c | 1078 ++++++++++++++++++++++++
 include/uapi/linux/usb/raw_gadget.h    |  167 ++++
 6 files changed, 1319 insertions(+)
 create mode 100644 Documentation/usb/raw-gadget.rst
 create mode 100644 drivers/usb/gadget/legacy/raw_gadget.c
 create mode 100644 include/uapi/linux/usb/raw_gadget.h

--
2.25.0.265.gbab2e86ba0-goog

#4 lore raw
Quoted 6 lines · Andrey Konovalov

Hi Greg, Felipe, and Alan,

I was wondering if there's a way to move forward with this patch?

Alan, since you have a very good knowledge of the USB subsystem, could I ask you to take a look at the patch, while Felipe is busy?

I'll look through the driver when I get a chance. That might not be for a while, though...

Alan Stern