syzkaller uses Raw Gadget and Dummy HCD/UDC to fuzz the Linux kernel USB stack.
As the interface provided by Raw Gadget is the same regardless of the used UDC, the reproducers for USB bugs generated by syzkaller when fuzzing with Dummy HCD/UDC can be run with any other UDC. Thus, these reproducers can be used to trigger buggy kernel behavior in physical USB hosts by using a Linux-based board that has a UDC.
This document contains the instructions on running syzkaller USB reproducers on a Linux-based board plugged into a physical USB host. These instructions were tested with Raspberry Pi boards, but any other board that has a working UDC can be used as well. These instructions were written for syzkaller revision b01b098ace00 (July 2nd 2024) and might need to be adapted for newer revisions.
-
Set up Raw Gadget on the board.
See Raw Gadget on Raspberry Pi for end-to-end instructions on how to set up Raw Gadget on a Raspberri Pi board;
-
On the host machine (not on the board), install Docker;
-
On the host, download syzkaller and set up
syz-env
:git clone https://github.com/google/syzkaller # Update '...' below. alias syz-env=".../syzkaller/tools/syz-env" cd syzkaller syz-env ls
syz-env
will take some time to set up the Docker image without providing any output; let it finish; -
Patch the UDC device and driver names in syzkaller to match the ones used on the board:
diff --git a/executor/common_usb_linux.h b/executor/common_usb_linux.h index b706663f8..f06fd5e3b 100644 --- a/executor/common_usb_linux.h +++ b/executor/common_usb_linux.h @@ -303,9 +303,7 @@ static volatile long syz_usb_connect_impl(uint64 speed, uint64 dev_len, const ch // TODO: consider creating two dummy_udc's per proc to increace the chance of // triggering interaction between multiple USB devices within the same program. - char device[32]; - sprintf(&device[0], "dummy_udc.%llu", procid); - int rv = usb_raw_init(fd, speed, "dummy_udc", &device[0]); + int rv = usb_raw_init(fd, speed, "20980000.usb", "20980000.usb"); if (rv < 0) { debug("syz_usb_connect: usb_raw_init failed with %d\n", rv); return rv;
-
Cross-compile
syz-execprog
andsyz-executor
:syz-env make generate syz-env GOARM=5 make TARGETARCH=arm execprog syz-env make TARGETARCH=arm executor
GOARM=5
is only required for boards that don't support hardware floating point instructions (such as Raspberry Pi Zero); -
Copy
./bin/linux_arm/syz-execprog
and./bin/linux_arm/syz-executor
onto the board.For a Raspberry Pi, one option to copy the files is to enable the SSH server via
sudo raspi-config
.Another option is to copy the files onto the SD card;
-
On the board, check that you can execute a simple syzkaller program:
$ cat socket.log r0 = socket$inet_tcp(0x2, 0x1, 0x0) $ sudo ./syz-execprog -executor ./syz-executor -threaded=0 -collide=0 -procs=1 -enable='' -debug socket.log
Make sure that you see these lines at the end of the output:
#0 [134ms] -> socket$inet_tcp(0x2, 0x1, 0x0) #0 [134ms] <- socket$inet_tcp=0x3
Seeing various failure messages before that is normal;
-
You should now be able to execute syzkaller USB programs:
$ cat usb.log r0 = syz_usb_connect(0x0, 0x24, &(0x7f00000001c0)={{0x12, 0x1, 0x0, 0x8e, 0x32, 0xf7, 0x20, 0xaf0, 0xd257, 0x4e87, 0x0, 0x0, 0x0, 0x1, [{{0x9, 0x2, 0x12, 0x1, 0x0, 0x0, 0x0, 0x0, [{{0x9, 0x4, 0xf, 0x0, 0x0, 0xff, 0xa5, 0x2c}}]}}]}}, 0x0) $ sudo ./syz-execprog -executor ./syz-executor -slowdown=3 -threaded=0 -collide=0 -procs=1 -enable='' -debug usb.log
The
slowdown
parameter is a scaling factor which can be used for increasing the syscall timeouts.Upon executing this program, a new USB device should appear on the host for a brief moment.
You now can get and run any pure USB bug reproducer from the ci2-upstream-usb
syzbot manager.
Note that pure USB reproducers should only contain pseudo-syscalls that start with syz_usb_
.
If a reproducer contains other syscalls, it requires interacting with the USB stack from the host side and thus cannot be executed via the described method.