Files
ferrix/fuzz/README.md
T
Rayhaan JaufeerallyandClaude Fable 5.1 39632e3c38 Property tests and fuzz targets for the parsers, and the bugs they found
Property tests (run by `cargo test`):
- crates/packet/tests/properties.rs: every kind of message, generated,
  must be written, be as long as wire_len says, and read back equal; and
  noise, noise behind a valid header, and valid messages with bytes damaged
  must never do more than return an error. Anything the decoder accepts
  must be showable and survive being written and read again.
- IpPrefix: text round trip, noise as text, `contains` against a bitwise
  model.
- The session's framing: a stream of messages yields the same messages
  however it is cut into reads.

Fuzz targets (fuzz/, cargo-fuzz on nightly, a minute each in CI): raw
messages, message bodies behind a valid header, prefix text, the
configuration file.

Bugs found, each with a named regression test:
- A prefix longer than its address family (e.g. an IPv4 NLRI of length 99)
  was accepted, and showing it panicked. The session logs every route, so
  one UPDATE from a peer ended the session task. Such a prefix is now
  malformed, and showing a prefix cannot fail.
- Bits past a prefix's length were kept, so the same prefix sent with stray
  bits was a different key in the RIB. Prefixes now have one form.
- An opaque extended community was read as seven octets instead of eight,
  putting every community after it out of step.
- AGGREGATOR could be neither read from nor written to a peer with
  two-octet AS numbers.
- The Outbound Route Filter and Long-Lived Graceful Restart capabilities
  were written differently from how they are read.
- A capability value or unknown attribute too long for its length field
  was written with the length wrapped around; it is now an error, or for
  the attribute the two-octet length.

Also: ROUTE-REFRESH carries its AFI and SAFI instead of being modelled as
an empty message, and one with a body of the wrong length is refused.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-01 22:54:37 +02:00

48 lines
1.8 KiB
Markdown

# Fuzz targets
Coverage-guided fuzzing of everything that reads input we do not control.
The property tests (`cargo test`, e.g. `crates/packet/tests/properties.rs`)
check the same things on generated input and run on every build; these
targets go further by letting libFuzzer follow code coverage for as long as
you leave them running.
| Target | Input |
|----------------|------------------------------------------------------------------|
| `message` | Raw bytes as they come off a TCP connection |
| `message_body` | A message body behind a correct header (reaches the body parsers) |
| `prefix_text` | A prefix as text |
| `config` | The configuration file |
For the two message targets a finding is either a panic, or a message the
decoder accepted that cannot be written and read back as itself.
## Running
libFuzzer needs a nightly toolchain and `cargo-fuzz`:
```bash
rustup toolchain install nightly
cargo install cargo-fuzz
```
Then, from this directory:
```bash
cargo +nightly fuzz run message_body corpus/message_body seeds/message_body -- -max_total_time=300
```
The first directory is the working corpus, which the fuzzer adds to and
which is not checked in. `seeds/` holds a few valid inputs to start from.
Leave out `-max_total_time` to run until interrupted.
## When it finds something
The input is saved under `artifacts/<target>/`. Reproduce it with
```bash
cargo +nightly fuzz run message_body artifacts/message_body/crash-...
```
Fix the bug, and add a unit test with the input next to the code it broke,
so that `cargo test` keeps it fixed without anyone having to run the fuzzer.