Files
alktunnels/fuzz
glm-5.3-flash 57285d23bd fuzz: adopt fuzzing (wave 1) + alkcall 0.8.1 bump
Bump the substrate dependency to alkcall 0.8.1 — the bug-fix release
whose fix (duplicate adopt/open no longer destroying the live channel)
is directly relevant to this crate's reverse-path adopt flow.

Adopt fuzzing per docs/research/fuzzing.md, scoped smaller than
alkcall's (the envelope/chunk/demux/manager surfaces are upstream and
now fuzzed there; this crate fuzzes its own named downstream target —
the ADR-003 datagram codec — plus the params/reply parsers):

- fuzz/ workspace per the alkcall pattern: nightly-pinned subtree
  (rust-toolchain.toml), thin fuzz_target! binaries, and a
  stable-toolchain shared crate carrying the invariant logic so the
  committed corpus replays as plain `cargo test` (the fuzz gate in
  the release checklist — no hosted CI, alkcall §7.9 posture).
- Targets (both over already-pub APIs; no #[cfg(fuzzing)] exposure):
  - datagram_codec — DatagramReader::feed + frame_datagram: no-panic,
    infallible decode, size bound, F-2 sentinel layering (empty
    datagram only from a length-0 header at a frame boundary),
    3-byte-slice splitting transparency, re-frame round-trip,
    oversize rejection at the bound, is_mid_datagram framing state,
    and the decoder-state retained-bytes bound.
  - params_parse — serde params/reply parsers + establishment_reason:
    no-panic on raw bytes and bounded structured Values, clean typed
    failure, round-trips, listen: 0 pin, loud/lenient projection-pair
    agreement, pass-through reason extraction model.
- New public diagnostic: DatagramReader::retained_bytes() (decoder-
  state byte count; the fuzz bound asserts against it).
- 96 committed seeds (gen_fuzz_seeds.py) + the campaign-found crash
  input promoted as datagram_codec/seed-900; grown corpora gitignored.
- run-detached.sh: setsid+nohup runner so campaigns never share fate
  with the agent session process tree (fuzzing.md §5).

Campaign findings this session were harness-model defects, not crate
bugs (both invisible to example-based review; the alkcall
"fuzzer as harness-checker" pattern confirmed):

- the F-2 empty-datagram invariant first counted [00 00] pairs in the
  raw stream — a pair inside a payload region is payload, not a
  header; corrected to walk the framing (crash artifact saved).
- establishment_reason is a pass-through extractor of details.reason,
  not a validated table (harness first asserted a closed set).
- is_mid_datagram means a partial datagram, not buffered header bytes
  (a 1-byte header fragment is buffered, not in flight).

Verification: cargo test 135 passed; clippy -D warnings and fmt clean
(main + fuzz/shared); corpus replay green; cargo fuzz build clean;
wasm32-unknown-unknown check clean. Wave-1 campaigns (10-min detached,
fork mode): params_parse 3.14M execs / datagram_codec 827k execs,
0 crashes/OOMs/timeouts; coverage saturated on the codec state space.
2026-09-28 08:09:11 +00:00
..

alktunnels fuzzing

libFuzzer targets for alktunnels' untrusted-input surfaces (see docs/research/fuzzing.md for the full rationale, scope decision, and campaign plan; the tooling/corpus/runner/no-CI posture is inherited from alkcall's docs/research/fuzzing.md).

Layout

  • fuzz_targets/ — one binary per target; thin fuzz_target! wrappers.
  • shared/ — the invariant logic, as a plain library so normal cargo test (stable toolchain) can replay the committed corpora through the same invariants (fuzz/shared/src/*.rs #[cfg(test)] modules; quinn's CI pattern). The fuzz binaries are nightly-only; the shared crate is stable-clean.
  • corpus/<target>/ — committed hand-made seeds (regenerate with python3 fuzz/gen_fuzz_seeds.py from the repo root). Grown corpora and artifacts are gitignored.
  • run-detached.sh — mandatory runner for agent sessions: wraps cargo fuzz run in setsid + nohup + log redirection so an OOM in a target can never take down the agent host (fuzzing.md §5).
  • json.dict — JSON token dictionary for the params target (transferred from alkcall).

Targets

Target Drives Invariants
datagram_codec DatagramReader::feed / frame_datagram (src/wire.rs) no-panic; infallible decode; yielded datagrams ≤ MAX_DATAGRAM_LEN; F-2 sentinel layering (empty datagram ≠ EOF, only from [00 00] headers); splitting transparency (3-byte slices == whole-input feed); re-frame round-trip; oversize rejection exactly at the bound; is_mid_datagram tracks framing; decoder-state retained-bytes bound
params_parse TunnelParams / TunnelDirectParams / TunnelForwardedParams / SubstrateAddr serde parses + parse_listen_reply / listen_reply_fields / establishment_reason (src/params.rs) no-panic on raw bytes and structured Values; clean typed failure only; round-trip for valid params; listen: 0 pin; loud/lenient projection-pair agreement; pinned establishment-reason table

Commands

cargo fuzz build and cargo fuzz run must be executed with fuzz/ (or deeper) as the working directory so rustup selects the pinned nightly toolchain — the detached runner handles that itself.

# build (nightly, pinned by rust-toolchain.toml inside fuzz/; run from fuzz/)
cargo fuzz build

# agent sessions: detached campaign (never foreground; CWD-independent)
FUZZ_RUNTIME_SECS=600 fuzz/run-detached.sh datagram_codec -max_len=65536
FUZZ_RUNTIME_SECS=600 fuzz/run-detached.sh params_parse -dict=json.dict -use_value_profile=1

# corpus replay through the invariants (stable toolchain, no nightly)
cargo test --manifest-path fuzz/shared/Cargo.toml

# coverage
cargo fuzz coverage <target>

The fuzz workspace is excluded from the main workspace and from the published package (exclude in the root Cargo.toml); it pins its own nightly toolchain via rust-toolchain.toml and does not affect the crate's stable MSRV.