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>
51 lines
2.0 KiB
Markdown
51 lines
2.0 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 |
|
|
| `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`:
|
|
|
|
```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.
|