Add a second fuzzing engine alongside the existing libFuzzer/cargo-fuzz setup. AFL++ runs with persistent mode (afl::fuzz! macro), LLVM plugins (CmpLog, IJON), and a SymCC concolic companion for hybrid fuzzing. - cargo-afl built from afl.rs with a patch for CARGO_AFL_DIR / CARGO_AFL_LLVM_DIR env-var overrides - AFL++ built with LLVM 22 plugins to match rust-nightly - Persistent-mode fuzz targets in lib/fuzz-afl/ - --jobs N parallel fuzzing: main instance in foreground, secondaries and SymCC companion as systemd transient units in a slice - Ctrl+c / exit cleans up all background processes via slice stop - AFL_AUTORESUME=1 for clean restarts after previous runs - fuzz-clean-afl collects crashes from all instance directories - Shared harness logic in lib/src/fuzz_harness.rs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
83 lines
4 KiB
Markdown
83 lines
4 KiB
Markdown
# CLAUDE.md
|
|
|
|
## Project overview
|
|
|
|
Rust USB/IP server library and CLI tool. Two workspace crates: `lib/` (library) and `cli/` (binary). Linux only.
|
|
|
|
## Security model
|
|
|
|
Host is trusted, client (in VM) is untrusted. All USB handling in userspace to minimize kernel attack surface. The host kernel's vhci_hcd driver is downstream of responses — don't assume it handles malformed data gracefully.
|
|
|
|
## Building
|
|
|
|
```bash
|
|
nix build # Nix
|
|
nix develop -c cargo build # Cargo via nix devShell
|
|
```
|
|
|
|
## Testing
|
|
|
|
```bash
|
|
nix develop -c cargo test -p usbip-rs
|
|
```
|
|
|
|
## Fuzzing
|
|
|
|
Fuzz targets exercise host-side codepaths against untrusted client input.
|
|
|
|
### libFuzzer (cargo-fuzz)
|
|
|
|
Targets are in `lib/fuzz-cargo/` and use `cargo fuzz`.
|
|
|
|
```bash
|
|
nix run .#fuzz-cargo # List targets
|
|
nix run .#fuzz-cargo -- fuzz_urb_hid # Single process
|
|
nix run .#fuzz-cargo -- fuzz_urb_hid --fork=8 # Parallel (overnight)
|
|
nix run .#fuzz-clean-cargo -- fuzz_urb_hid # Prune fixed artifacts
|
|
```
|
|
|
|
Crash artifacts: `lib/fuzz-cargo/artifacts/<target>/`.
|
|
|
|
### AFL++ with cargo-afl
|
|
|
|
Targets are in `lib/fuzz-afl/` and use `cargo-afl` with LLVM plugins for persistent mode, CmpLog, and IJON. AFL++ runs as the primary fuzzer with CmpLog auto-enabled (`-c0`); a SymCC-instrumented binary is also built for manual concolic execution.
|
|
|
|
```bash
|
|
nix run .#fuzz-afl # List targets
|
|
nix run .#fuzz-afl -- fuzz_urb_hid # Run AFL++ (persistent + CmpLog)
|
|
nix run .#fuzz-afl -- fuzz_urb_hid --jobs=8 # Parallel (main + 7 secondaries)
|
|
nix run .#fuzz-clean-afl -- fuzz_urb_hid # Prune fixed crashes
|
|
```
|
|
|
|
The Nix package for `cargo-afl` is built in this repo from `rust-fuzz/afl.rs` with a patch adding `CARGO_AFL_DIR` / `CARGO_AFL_LLVM_DIR` env var overrides (see `nix/cargo-afl-env-paths.patch`). AFL++ is built with LLVM 22 plugins to match rust-nightly's LLVM version.
|
|
|
|
Background processes (secondary AFL++ instances, SymCC companion) run as systemd transient units in a slice. Ctrl+c or exit cleans up everything; `systemctl --user stop fuzz_afl_<target>.slice` for manual stop.
|
|
|
|
Crashes: `lib/fuzz-afl/output/<target>/*/crashes/`. Corpora are separate between engines; copy manually if desired.
|
|
|
|
### Shared harness
|
|
|
|
All fuzz target logic lives in `lib/src/fuzz_harness.rs`. Response validation is in `lib/src/fuzz_helpers.rs`.
|
|
|
|
### Fixing fuzzer crashes
|
|
|
|
1. **Priority**: Protect the host process and host kernel from untrusted client gaining code execution or privilege escalation. DoS is not a concern — the client would only be DoSing its own service.
|
|
2. **Check reachability**: Determine whether the crashing state can be reached by a normal, well-behaved client (check the Linux kernel USB/IP source at `../linux/drivers/usb/usbip/` and `../linux/tools/usb/usbip/`). If not reachable by a well-behaved client, return an error rather than continuing to process garbage.
|
|
3. **No `unsafe`** in parsing or sanitization paths.
|
|
4. **Validate at the boundary**: Check constraints immediately after deserialization, not deep in business logic.
|
|
5. **Update fuzz assertions**: Tighten the invariant assertions in `lib/src/fuzz_helpers.rs` whenever you add or change a constraint — the fuzzer can only find violations it can check.
|
|
6. We are using our own nusb fork, and API compatibility is not a concern. If an issue is better fixed in nusb, stop and explain the situation.
|
|
|
|
## Key architecture
|
|
|
|
- `handle_urb_loop()` — main URB dispatch loop, generic over async transport
|
|
- `handler()` — full connection handler (negotiation + URB loop), takes `UsbIpServer`
|
|
- `UsbInterfaceHandler` trait — implement for new device types
|
|
- Protocol parsing in `usbip_protocol.rs`, device model in `device.rs`
|
|
- `MockSocket` in `util::mock` — used by both tests and fuzz targets
|
|
|
|
## Conventions
|
|
|
|
- No backwards compatibility concerns for the library API
|
|
- `pub use` re-exports from `lib.rs` — e.g. `mock` module is available as `usbip_rs::mock::MockSocket`
|
|
- Edition 2024
|