## Fuzzing passt with AFL++ ### Prerequisites - AFL++ (afl-clang-fast, afl-fuzz) - Linux kernel with `CONFIG_USER_NS=y` (default on Fedora, Debian, Ubuntu) ### Build ``` make fuzz # AFL++-instrumented binary (produces passt.fuzz) ``` This also builds `fuzz-server` (the host-side test peer) as a prerequisite. This produces: - `passt.fuzz` -- instrumented with AFL++ and AddressSanitizer - `fuzz-server` -- host-side test peer (built automatically) To use a specific AFL++ installation: ``` make FUZZ_CC=/path/to/afl-clang-fast fuzz ``` ### Network setup The fuzzer runs in a rootless user + network namespace with AnyIP routing so the test server intercepts all outbound IPv4 and IPv6 TCP from passt, regardless of destination IP or port. No root access is needed -- `fuzz-setup.sh` uses `unshare --user --net` to create the namespace pair, matching how pasta itself operates. The test server listens on ports 1 through 55535 (both IPv4 and IPv6), leaving the top 10000 ports free for passt's own `connect()` and `bind()` calls. The namespace exists only while the command runs; no cleanup step is required. ### Run passt automatically fork+execs `fuzz-server` before the AFL++ forkserver starts, then sleeps 3 seconds to let it finish binding all ports. There is no need to launch it separately. Basic run: ``` fuzzing/fuzz-setup.sh -- afl-fuzz -i fuzzing/testcase_dir \ -o fuzzing/sync_dir -- ./passt.fuzz --foreground ``` Multi-core (secondary instances share the corpus): ``` # Terminal 1 -- main instance: fuzzing/fuzz-setup.sh -- afl-fuzz -M main \ -i fuzzing/testcase_dir -o fuzzing/sync_dir \ -- ./passt.fuzz --foreground # Terminal 2 -- secondary with different power schedule: fuzzing/fuzz-setup.sh -- afl-fuzz -S variant1 -p rare \ -i fuzzing/testcase_dir -o fuzzing/sync_dir \ -- ./passt.fuzz --foreground ``` ### Architecture AFL++ controls four regions of the testcase buffer: - **(a) `ev`** -- array of epoll events injected into passt's main loop alongside real kernel events - **(b) `buf`** -- raw tap-side packets (full L2 frames, headers included). AFL++ controls everything: Ethernet, IP, TCP/UDP headers, destination addresses, payload - **(c) `test_buf`** -- payload the test server sends to passt on accepted connections - **(d) `sockopt_buf`** -- TCP_INFO data returned to passt by the `getsockopt()` wrapper in fuzz.c The testcase header carries explicit lengths for each region: `n_events` (u32), `tap_len` (u16), `testbuf_len` (u16), and `sockopt_len` (u16). Both passt and `fuzz-server` call `fuzz_parse_layout()` on the same header, which clamps each declared length to the available space and to per-region maximums, so the two sides always agree on offsets. AFL++ controls the split directly through mutation of these header fields. Example flow for a single event: 1. AFL++ writes an EPOLLIN event with type EPOLL_TYPE_TAP_PASST in `ev`, raw packet data in `buf`, and payload in `test_buf` 2. passt reads the event from `ev`, reads data from `buf`, and hands it to tap_handler() 3. The data happens to have Ethernet, IP, and TCP headers with the SYN flag set (AFL++ discovered this format). passt calls connect() to the destination in the packet 4. AnyIP routing makes the destination local and the test server, which listens on ports 1-55535 (IPv4+IPv6), accepts the connection 5. The test server sends the contents of `test_buf` to passt 6. A real epoll_wait() fires EPOLLOUT for passt (not from `ev`) 7. passt marks the connection established and inserts it in the flow table 8. passt reads data from the test server and generates TCP data back to the "guest" ### Seed inputs `testcase_dir/empty.bin` provides a minimal starting point. AFL++ discovers packet formats through mutation. ### Reproducing crashes Replay a crash input (`fuzz-server` is fork+exec'd by passt automatically): ``` fuzzing/fuzz-setup.sh -- ./passt.fuzz --foreground < \ fuzzing/sync_dir/default/crashes/id:000000,... ``` Minimize a crash input: ``` fuzzing/fuzz-setup.sh -- afl-tmin \ -i fuzzing/sync_dir/default/crashes/id:000000,... \ -o crash_minimized -- ./passt.fuzz --foreground ```