Raw Gadget
Note: Raw Gadget is a debugging feature, and it should not be used in production. Use GadgetFS instead. See the differences here.
Raw Gadget is a Linux kernel module that implements a low-level interface for the Linux USB Gadget subsystem.
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 dummy_hcd and raw_gadget 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:
- Make sure that all required backend callbacks are implemented. For example,
read_from_endpoint
should probably be implemented. - Provide a common Python wrapper for Raw Gadget ioctls, and use it in the backend.
- 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 generic guidance to troubleshooting Raw Gadget errors:
-
Switch to the dev branch.
This branch contains fixes for some known issues and prints more debug output.
-
Enable debug output for Raw Gadget (and Dummy HCD/UDC if you're using it).
Add the following line to the very beginning of
raw_gadget/raw_gadget.c
:#define DEBUG
Rebuild and reinsert the module.
-
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 likely means that the emulated USB device did something wrong. For example, tried to perform an endpoint operation before the device is configured. Or provided an endpoint descriptor that does not match the USB device speed. As a result, either the UDC driver or the host decided to disconnect the device.
Note: During device operation, the host might decide to reconfigure the device.
The UDC driver will then issue a reset or a disconnect event (depends on which UDC driver is in use).
After this, endpoint operations will fail with ESHUTDOWN
until the device emulation code calls USB_RAW_IOCTL_CONFIGURE
again when handling a new SET_CONFIGURATION
request.
Getting notifications about the reset and disconnect events requires using the Raw Gadget patches from the dev branch.
Projects based on Raw Gadget
- google/syzkaller — a kernel fuzzer, uses Raw Gadget for fuzzing Linux kernel USB drivers.
- AristoChen/usb-proxy — A USB proxy based on Raw Gadget and libusb.
- blegas78/usb-sniffify — Another USB proxy based on Raw Gadget and libusb.
- patryk4815/usb-proxy — A USB proxy based on Raw Gadget and written in Go.
TODO
Other potential fixes/improvements to investigate:
- Set
ep->maxburst
,ep->mult
andep->maxpacket
in gadget drivers. - OTG support.
- Set
ep->dev
onep
allocation. - Don't pass
ep0_status
andep_status
throughdev
, get fromreq
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.