Files
ferrix/fuzz/README.md
T
Rayhaan JaufeerallyandClaude Fable 5.1 3d946c32ce Code health after review: docs, metrics, structure, one more fuzz target
What the code-health review found, and what a fuzz target written for it
found in its first seconds.

- A set of attributes with the same attribute twice is refused by the
  routing table. Its readers (the selection key, the path, the next hop)
  could each take a different one of the two. The decoder never lets one
  through; the new fuzz target `attrs` found that the table would.
- bgp_peer_up{peer}, to alert on a peer going away, and bgp_build_info.
  Every metric is there from the first scrape. Alerts for a peer down,
  hijack attempts and kernel errors are in the README.
- `bgp --check config` validates a configuration without starting, and
  `--version` says which build it is. CI runs the first on the example
  configuration, which a test now also parses with its commented fields
  put in; the example had to learn about the next hop check.
- Path attributes have a module of their own, packet::attributes,
  re-exported from packet::message as before.
- policy::From, which shadowed the trait, is RouteSource. The server's
  connection, dialer and fsm modules are private. Logging arguments live
  in the binary; the server library no longer depends on clap.
- One is_unicast_link_local (the standard library's) instead of two of
  our own; SelectionKey::origin(); one place where an Import is made.
- READMEs say what the daemon does today rather than what it did not do
  a year ago. Documentation links are checked in CI. Unused dependencies
  and bgp_web::serve are gone; the Docker build is --locked and does not
  ship the fuzz corpus.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-02 19:31:19 +02:00

2.0 KiB

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
rtr A stream of RTR PDUs, as an RPKI cache sends them
netlink Messages from the kernel's routing socket
attrs The routing table's reading of stored attribute bytes

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:

rustup toolchain install nightly
cargo install cargo-fuzz

Then, from this directory:

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

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.