Skip to content

USB Raw Gadget — a low-level interface for the Linux USB Gadget subsystem

Notifications You must be signed in to change notification settings

antoniprzybylik/raw-gadget

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

60 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Raw Gadget

Note: Do not use Raw Gadget in production for emulating USB devices with concrete classes. Instead, use the composite framework or the legacy gadget driver modules. Raw Gadget is intended for fuzzing and exploiting USB hosts or for proxying USB devices.

Raw Gadget is a Linux kernel module that implements a low-level interface for the Linux USB Gadget subsystem. It is similar to GadgetFS, but provides greater flexibility; see all the differences here.

Raw Gadget can be used to emulate USB devices, both physical and virtual ones. Emulating physical devices requires a Linux board with a USB Device Controller (UDC), such as a Raspberry Pi. Emulating virtual devices requires no hardware and instead relies on the Dummy HCD/UDC module (such devices get connected to the kernel Raw Gadget is running on).

This repository contains instructions and examples for using Raw Gadget.

Raw Gadget has been merged into the mainline Linux kernel in 5.7. There's no need to use 5.7+ kernels; see raw_gadget and dummy_hcd for information on how to build and insmod corresponding modules on older kernels. The modules should be compatible with kernel versions down to 4.14; see the table below.

Building the Raw Gadget and Dummy HCD/UDC kernel modules requires kernel headers. On desktop Ubuntu, you can get them by installing linux-headers-`uname -r`. On a Raspberry Pi, follow these instructions.

See the Fuzzing USB with Raw Gadget talk [video] for details about Linux Host and Gadget USB subsystems and Raw Gadget.

USB Device Controllers

Raw Gadget requires the user to provide the UDC device and driver names. This allows using Raw Gadget with a particular UDC if a few of them are present on the system.

UDC device names can be found in /sys/class/udc/:

$ ls /sys/class/udc/
dummy_udc.0

The UDC driver name is usually present in /sys/class/udc/$UDC/uevent:

$ cat /sys/class/udc/dummy_udc.0/uevent
USB_UDC_NAME=dummy_udc

Below is a table of UDCs that were tested with Raw Gadget.

Hardware Kernel Driver Device Works?
5.3.0-45-generic dummy_udc dummy_udc.0 Yes
Raspberry Pi Zero 4.14.97+ 20980000.usb 20980000.usb (dwc2) Yes
Raspberry Pi 4 5.10.63-v7l+ fe980000.usb fe980000.usb (dwc2) Yes
USB Armory MkII 5.4.87-0 2184000.usb ci_hdrc.0 Yes
Orange Pi PC 5.10.60 musb-hdrc musb-hdrc.4.auto Yes
Orange Pi PC 2 5.10.60 musb-hdrc musb-hdrc.4.auto Yes
Khadas VIM1 5.10.60-meson64 c9100000.usb c9100000.usb Yes
BeagleBone Black 4.19.94-ti-r42 musb-hdrc musb-hdrc.0 Probably
BeagleBone AI 4.14.108-ti-r131 48890000.usb dwc3-gadget Not yet
EC3380-AB 5.3.0-45-generic net2280 0000:04:00.0 (e.g.) Partially,
net2280 buggy
Odroid C2 3.14.79-116 dwc_otg_pcd dwc2_a No, kernel too old

"Works" in the table above means that the UDC passes the provided tests, which only cover a subset of functionality.

Facedancer backend

There's a prototype of a Facedancer backend based on Raw Gadget.

This backend relies on a few out-of-tree Raw Gadget patches present in the dev branch. Once the backend is thoroughly tested, these patches will be submitted to the mainline.

Raw Gadget-based backend accepts a few parameters through environment variables:

Parameter Description Default value
RG_UDC_DRIVER UDC driver name dummy_udc
RG_UDC_DEVICE UDC device name dummy_udc.0
RG_USB_SPEED USB device speed 3 (High Speed)

Example of using Facedancer with Raw Gadget to emulate a USB keyboard on a Raspberry Pi 4:

export BACKEND=rawgadget
export RG_UDC_DRIVER=fe980000.usb
export RG_UDC_DEVICE=fe980000.usb
./legacy-applets/facedancer-keyboard.py

Note: Some Facedancer examples might fail if a wrong USB speed is specified. Failures happen either with EINVAL in USB_RAW_IOCTL_EP_ENABLE, with ESHUTDOWN in USB_RAW_IOCTL_EP_READ/WRITE, or can be completely random. For example, with Dummy UDC, examples/ftdi-echo.py requires RG_USB_SPEED=2 and legacy-applets/facedancer-ftdi.py requires RG_USB_SPEED=3. In turn, legacy-applets/facedancer-umass.py requires RG_USB_SPEED=2.

Note: This backend is still a prototype. Outstanding tasks:

  1. Make sure that all required backend callbacks are implemented. For example, read_from_endpoint should probably be implemented.
  2. Provide a common Python wrapper for Raw Gadget ioctls, and use it in the backend.
  3. Finalize and submit out-of-tree Raw Gadget patches to the mainline.

Note: Facedancer assumes that every backend supports non-blocking I/O, which is not the case for Raw Gadget. To work around this limitation, the backend prototype relies on timeouts. The proper solution to this issue would be to add non-blocking I/O support to Raw Gadget.

Troubleshooting

As a generic guidance to troubleshooting Raw Gadget errors:

  1. Switch to the dev branch.

    This branch contains fixes for some known issues and prints more debug output.

  2. Enable debug output for Raw Gadget (and Dummy HCD/UDC if you're using it).

    To do this, add the following line to the very beginning of raw_gadget/raw_gadget.c:

    #define DEBUG

    Then rebuild and reinsert the module.

  3. Check the kernel log via dmesg to figure out what is failing.

No such device

USB_RAW_IOCTL_RUN returns ENODEV, error code 19:

ioctl(USB_RAW_IOCTL_RUN): No such device

This error means that bad UDC driver/device names were provided. Make sure that the UDC driver module is loaded. Also see USB Device Controllers about UDC names.

Cannot send after transport endpoint shutdown

Endpoint operations return ESHUTDOWN, error code 108:

ioctl(USB_RAW_IOCTL_EP0_WRITE): Cannot send after transport endpoint shutdown

This error means that the emulated USB device tried to perform a read or write operation on a disabled endpoint.

This error is usually observed when the host decides to reset the device during its operation.

A reset often happens when the device emulation code does something wrong. For example, provides a bad descriptor that gets rejected by the host. As a result, either the UDC driver or the host decides to reset the device.

Note that a reset can happen during normal device operation. For example, when the host decides to reconfigure the device. The UDC driver will then issue a reset event (or disconnect for dwc2). After this, any attempt to perform an endpoint operation will fail with ESHUTDOWN until the device emulation code calls USB_RAW_IOCTL_CONFIGURE again when handling a new SET_CONFIGURATION request. The device emulation code needs to gracefully handle ESHUTDOWN and restart enumeration.

Projects based on Raw Gadget

TODO

Other potential fixes/improvements to investigate:

  • Set ep->maxburst, ep->mult and ep->maxpacket in gadget drivers.
  • OTG support.
  • Set ep->dev on ep allocation.
  • Don't pass ep0_status and ep_status through dev, get from req instead.

License

The parts of code in this repository that are derived from the Linux kernel are covered by GPL-2.0. Everything else is covered by Apache-2.0. SPDX-License-Identifier marks the used license in each file.

About

USB Raw Gadget — a low-level interface for the Linux USB Gadget subsystem

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C 95.9%
  • Python 2.4%
  • Shell 1.2%
  • Makefile 0.5%