feat(fuzz): cargo-fuzz workspace, 3 wire-surface targets; bump alkcall 0.8.1
- Bump alkcall 0.8.0 -> 0.8.1 (duplicate adopt/open channel-state destruction fix from alkcall's fuzz campaign; AGENTS.md stale-pin fix). - Adopt fuzzing per docs/plans/fuzzing.md (mirrors alkcall's docs/research/fuzzing.md as-built layout): fuzz/ workspace with own [workspace] table, nightly pinned for the subtree only, invariant logic in a stable-toolchain shared crate. - Targets: chunk_frame (5-byte chunk codec), negotiation_frame (negotiation framing + NegotiateRequest + error_response_bytes + the cross-codec peek-disambiguation seam), control_json (ControlMessage JSON + signal_from_name). src/local/ out of scope (not wire-attacker-shaped). - 328 committed seeds (deterministic generator); grown corpora gitignored. Corpus replay on stable is the standing fuzz gate (cargo test --manifest-path fuzz/shared/Cargo.toml). - Detached-runner rule (fuzz/run-detached.sh): campaigns never run in the foreground of an agent session - OOM in a target must cost the fuzzer, never the session host. - Root Cargo.toml gained [workspace] members/exclude (MSRV vs fuzz nightly dev-deps footgun) and fuzz/ in the publish exclude. Verification: cargo test (113), cargo test --all-features (156), clippy stable + wasm32-unknown-unknown, fmt, doc, publish dry-run, corpus replay 328 seeds - all green. 10-min detached campaigns on all three targets: 0 crashes/hangs/OOMs/leaks (chunk_frame cov-saturated at 710 edges; negotiation_frame 3.69M execs cov 3157; control_json 8.6M execs cov 2035). Corpus replay caught three harness-model mismatches pre-campaign (payload-slice shape; the negotiation framing layer is length-prefix-only - Json unreachable from read_frame; zero-length frames admitted by the reader, rejected by the adapter's parse). Campaigns recorded in docs/plans/fuzzing.md section 8.
This commit is contained in:
1 parent
e95459c425
commit
49f70d9efb
1809 files changed
+9380
-12
No files matched your search
@@ -0,0 +1,7 @@
|
||||
target
|
||||
corpus/*
|
||||
!corpus/chunk_frame
|
||||
!corpus/negotiation_frame
|
||||
!corpus/control_json
|
||||
artifacts
|
||||
coverage
|
||||
Generated
+1312
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,38 @@
|
||||
[package]
|
||||
name = "alktty-fuzz"
|
||||
version = "0.0.0"
|
||||
publish = false
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
libfuzzer-sys = "0.4"
|
||||
alktty-fuzz-shared = { path = "shared" }
|
||||
|
||||
[dependencies.alktty]
|
||||
path = ".."
|
||||
|
||||
[[bin]]
|
||||
name = "chunk_frame"
|
||||
path = "fuzz_targets/chunk_frame.rs"
|
||||
test = false
|
||||
doc = false
|
||||
bench = false
|
||||
|
||||
[[bin]]
|
||||
name = "negotiation_frame"
|
||||
path = "fuzz_targets/negotiation_frame.rs"
|
||||
test = false
|
||||
doc = false
|
||||
bench = false
|
||||
|
||||
[[bin]]
|
||||
name = "control_json"
|
||||
path = "fuzz_targets/control_json.rs"
|
||||
test = false
|
||||
doc = false
|
||||
bench = false
|
||||
|
||||
[workspace]
|
||||
@@ -0,0 +1,60 @@
|
||||
# alktty fuzzing
|
||||
|
||||
cargo-fuzz targets for the wire-facing parse surfaces. The design and
|
||||
operating rules live in `docs/plans/fuzzing.md` (adopted from alkcall's
|
||||
`docs/research/fuzzing.md`); this README is the operational cheat-sheet.
|
||||
|
||||
## Layout
|
||||
|
||||
- `fuzz_targets/` — nightly-only `fuzz_target!` binaries (thin wrappers).
|
||||
- `shared/` — stable-toolchain library holding the invariant logic; the
|
||||
corpus replay tests run here on plain `cargo test`.
|
||||
- `corpus/<target>/` — committed seeds (regenerate with
|
||||
`python3 fuzz/gen_fuzz_seeds.py`).
|
||||
- `artifacts/` — gitignored crash/oom/timeout artifacts + campaign logs.
|
||||
|
||||
## Targets
|
||||
|
||||
| Target | Drives |
|
||||
|---|---|
|
||||
| `chunk_frame` | `ChunkReader`/`ChunkWriter` (5-byte chunk codec, ADR-001) |
|
||||
| `negotiation_frame` | `NegotiationReader`/`NegotiationWriter` + `NegotiateRequest` + `error_response_bytes` + the cross-codec peek-disambiguation seam |
|
||||
| `control_json` | `ControlMessage::from_slice`/`to_json` + `signal_from_name` |
|
||||
|
||||
## Running a campaign — always detached
|
||||
|
||||
Agent sessions must never run fuzzing in the foreground (an OOM in a
|
||||
target can take down the session host; see docs/plans/fuzzing.md §3).
|
||||
Use the detached runner:
|
||||
|
||||
```bash
|
||||
fuzz/run-detached.sh chunk_frame
|
||||
# poll:
|
||||
tail -n 50 fuzz/artifacts/chunk_frame-*.log
|
||||
ls fuzz/artifacts/chunk_frame/
|
||||
pgrep -f "cargo fuzz run chunk_frame"
|
||||
```
|
||||
|
||||
`FUZZ_RUNTIME_SECS=1800 fuzz/run-detached.sh negotiation_frame` for a
|
||||
longer campaign. The runner pins `-fork=1 -rss_limit_mb=2048
|
||||
-malloc_limit_mb=2048 -timeout=25` and detaches via `setsid` + `nohup`.
|
||||
|
||||
## Corpus replay (the standing fuzz gate)
|
||||
|
||||
```bash
|
||||
cargo test --manifest-path fuzz/shared/Cargo.toml
|
||||
```
|
||||
|
||||
Replays every committed seed through the same invariant functions the
|
||||
fuzzer runs, on stable, no nightly needed. Part of the release
|
||||
verification checklist (AGENTS.md).
|
||||
|
||||
## Toolchain notes
|
||||
|
||||
`rust-toolchain.toml` pins nightly for this subtree only (llvm-tools
|
||||
required by cargo-fuzz); the crate itself stays on stable at MSRV 1.88.
|
||||
`cargo fuzz build` must be run with the fuzz dir as CWD or trust the
|
||||
toolchain file (rustup resolves per directory).
|
||||
|
||||
Run campaigns before releases and after touching `src/wire.rs`,
|
||||
`src/negotiation.rs`, `src/control.rs`, the adapter, or the session pump.
|
||||
Whitespace-only changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loaded 100 of 1809 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user