USB Raw Gadget

USB Raw Gadget is a gadget driver that gives userspace low-level control over the gadget’s communication process.

Like any other gadget driver, Raw Gadget implements USB devices via the USB gadget API. Unlike most gadget drivers, Raw Gadget does not implement any concrete USB functions itself but requires userspace to do that.

Raw Gadget is currently a strictly debugging feature and should not be used in production. Use GadgetFS instead.


Comparison to GadgetFS

Raw Gadget is similar to GadgetFS but provides more direct access to the USB gadget layer for userspace. The key differences are:

  1. Raw Gadget passes every USB request to userspace to get a response, while GadgetFS responds to some USB requests internally based on the provided descriptors. Note that the UDC driver might respond to some requests on its own and never forward them to the gadget layer.

  2. Raw Gadget allows providing arbitrary data as responses to USB requests, while GadgetFS performs sanity checks on the provided USB descriptors. This makes Raw Gadget suitable for fuzzing by providing malformed 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. This allows having multiple Raw Gadget instances bound to different UDCs.

  4. Raw Gadget explicitly exposes information about endpoints addresses and capabilities. This allows the user to write UDC-agnostic gadgets.

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

Userspace interface

The user can interact with Raw Gadget by opening /dev/raw-gadget and issuing ioctl calls; see the comments in include/uapi/linux/usb/raw_gadget.h for details. Multiple Raw Gadget instances (bound to different UDCs) can be used at the same time.

A typical usage scenario of Raw Gadget:

  1. Create a Raw Gadget instance by opening /dev/raw-gadget.

  2. Initialize the instance via USB_RAW_IOCTL_INIT.

  3. Launch the instance with USB_RAW_IOCTL_RUN.

  4. In a loop issue USB_RAW_IOCTL_EVENT_FETCH to receive events from Raw Gadget and react to those depending on what kind of USB gadget must be implemented.

Note that some UDC drivers have fixed addresses assigned to endpoints, and therefore arbitrary endpoint addresses cannot be used in the descriptors. Nevertheless, Raw Gadget provides a UDC-agnostic way to write USB gadgets. Once USB_RAW_EVENT_CONNECT is received via USB_RAW_IOCTL_EVENT_FETCH, USB_RAW_IOCTL_EPS_INFO can be used to find out information about the endpoints that the UDC driver has. Based on that, userspace must choose UDC endpoints for the gadget and assign addresses in the endpoint descriptors correspondingly.

Raw Gadget usage examples and a test suite:

Internal details

Every Raw Gadget endpoint read/write ioctl submits a USB request and waits until its completion. This is done deliberately to assist with coverage-guided fuzzing by having a single syscall fully process a single USB request. This feature must be kept in the implementation.

Potential future improvements

  • Report more events (suspend, resume, etc.) through USB_RAW_IOCTL_EVENT_FETCH.

  • Support O_NONBLOCK I/O. This would be another mode of operation, where Raw Gadget would not wait until the completion of each USB request.

  • Support USB 3 features (accept SS endpoint companion descriptor when enabling endpoints; allow providing stream_id for bulk transfers).

  • Support ISO transfer features (expose frame_number for completed requests).