Skip to content

test(fuzz): hostile peer bytes never panic an adapter - #561

Merged
kixelated merged 5 commits into
mainfrom
quest/m2/confidence/adapters-hostile-input
Nov 10, 2026
Merged

kixelated merged 5 commits into
mainfrom
quest/m2/confidence/adapters-hostile-input

Conversation

@kixelated

@kixelated kixelated commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Claims quest/m2/confidence/adapters-hostile-input.md.

Summary

Three fuzz targets, one per adapter, feed each one what a network peer controls. Each answer is compared with the upstream's own aws-lc-rs provider:

  • fuzz::rustls: TLS 1.2 and 1.3 records, QUIC packets and header protection, key shares for every group (hybrids and ML-KEM included, as server and as client), session tickets, and signature verification for every algorithm. It also runs whole handshakes between a rind client and a rind server (TLS 1.2 or 1.3, any suite and group, five key types, optional client auth), with the bytes of each flight edited in flight.
  • fuzz::dimpl: DTLS 1.2 and 1.3 records, record-number masks, key shares, and verify_signature on the peer's certificate. It also runs whole DTLS 1.2 and 1.3 handshakes between two rind endpoints, with each packet edited in flight.
  • fuzz::str0m: AES-CM, AES-128-GCM and AES-256-GCM decryption, called in the shapes str0m's unprotect_rtp and unprotect_rtcp use, plus the HMAC-SHA1 that covers SRTP.

A failed open must leave each byte of the caller's buffer either as the peer sent it or zero. A panic, a hang, or an answer that differs from aws-lc-rs's fails the run. fuzz.yml picks the targets up from cargo fuzz list, so they run nightly and replay on every tier.

TESTING.md gets an Adapters section, and admin/testing accepts the targets it names.

Public API and wire impact: none. This touches only the unpublished fuzz crate, docs and admin/testing.

Choices made without asking

  • One target per adapter, with the handshake as one of its input types. This avoids two more nightly jobs plus their replays.
  • No seed files. Each input starts from a genuine sealed record, key share, ticket, signature or handshake and then edits it, so the fuzzer starts past the first length check. Handshakes use fresh random keys, so a crash found there may not reproduce byte for byte.
  • rustls can only build a 32-byte AeadKey outside its key schedule, so TLS records are fuzzed directly under the 32-byte suites. The AES-128 suites share the same decrypters and are reached through QUIC's derived keys and the handshakes. Lengths only a direct trait caller could pass, such as a mis-sized key, are left out and the targets say so.
  • The plaintext check applies to authentication failures only. A record that authenticates and then is refused as oversized holds the peer's own plaintext, which matches aws-lc-rs's behavior.
  • str0m keeps its SRTP packet code private, so str0m calls the cipher traits the way that code does. Key derivation (srtp_aes_*_ecb_round) reads no peer bytes, so it is left out.
  • Built locally with RUSTC_BOOTSTRAP=1 on the stable dev-shell toolchain, since the flake has no nightly. CI uses nightly as before.

Interactions

  • moq-dev/rind#519 makes default_provider() infallible in rind-dimpl and rind-str0m. Whichever PR merges second drops two .unwrap() calls in fuzz/fuzzer/dimpl.rs and fuzz/fuzzer/str0m.rs.
  • moq-dev/rind#535 merged first. Main is merged in here, and admin/testing now checks main's Zeroing column alongside the adapters line.

Fuzz runs

Built with cargo fuzz build -O and run locally: str0m for 5 minutes (4.4M runs), dimpl for 5 (153k), rustls for 10 (292k). None panicked in an adapter. The first runs failed on harness checks that were stricter than the contract. They are narrowed now, and the review added the oversized case:

  • rustls sealed TLS 1.3 records of content type 0 and ChangeCipherSpec. rustls refuses both inside a record (IllegalTlsInnerPlaintext, IllegalMiddleboxChangeCipherSpec), and aws-lc-rs agreed, so the target now seals only Alert, Handshake, and ApplicationData.
  • dimpl's encrypt_sn for ChaCha20 differs after byte 5. rind returns the whole keystream block, as dimpl's rust_crypto provider does. dimpl's aws-lc-rs provider returns QUIC's 5-byte mask and zero after it. dimpl XORs at most two mask bytes over the sequence number, so the target compares the first five.
  • An unedited TLS record over rustls's 16 KiB fragment limit must fail with PeerSentOversizedRecord instead of opening.

The quest file is deleted, and its links in the confidence README and the rustls panic-trace quest are gone.

Models

Size: M
Implementer: Claude Code, claude-opus-5-5, medium effort
Implementer: Claude Code, claude-opus-5-5, medium effort (iterate, M)

🤖 Generated with Claude Code

(Written by Claude Opus 5.5 with medium)

Review

Rewritten by quest review after each round.

  • Reviewer: Codex, gpt-6.1-sol, medium effort
  • Session: 01a1c6d9-ff96-7e03-8a95-f4a60b9aa708, round 3
  • Head: 3531369
  • Base: origin/main at 6e8239e
  • Score: 10/10, The merge preserves the reviewed fuzz targets and correctly combines the adapter coverage checks with main’s testing updates, with no new findings.
  • Findings: none

kixelated and others added 2 commits November 9, 2026 20:10
…str0m

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title Hostile peer bytes never panic an adapter test(fuzz): hostile peer bytes never panic an adapter Nov 10, 2026
kixelated and others added 2 commits November 10, 2026 10:55
- rustls: seal only the content types a TLS 1.3 peer seals; rustls
  refuses type 0 and an inner ChangeCipherSpec, as aws-lc-rs does.
- dimpl: compare the five mask bytes both providers fill; aws-lc-rs's
  ChaCha20 `encrypt_sn` zeroes the rest, and dimpl reads at most two.

Deletes the finished quest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review November 10, 2026 19:15
@pullfrog

pullfrog Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Your OpenCode Go account is out of credit. Top it up, then re-trigger Pullfrog.

OpenCode Go's response
provider error: Insufficient balance (402)

Top up OpenCode Go →

Pullfrog  | Rerun failed job ➔ | View workflow run | via Pullfrog | Using glm-5.3

@coderabbitai

coderabbitai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 57 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1f962a24-7213-49f1-bded-b64429660622
Commits

Reviewing files that changed from the base of the PR and between 6e8239e and 3531369.

Files ignored due to path filters: 1

  • Cargo.lock is excluded by !**/*.lock
Files selected for processing: 8

  • TESTING.md
  • admin/testing
  • fuzz/Cargo.toml
  • fuzz/fuzzer/dimpl.rs
  • fuzz/fuzzer/rustls.rs
  • fuzz/fuzzer/str0m.rs
  • quest/m2/confidence/README.md
  • quest/m2/confidence/adapters-hostile-input.md
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

…dapters-hostile-input

# Conflicts:
#	admin/testing
#	quest/m2/confidence/adapters-hostile-input.md
#	quest/m2/confidence/rustls-provider-panics.md
@kixelated
kixelated added this pull request to the merge queue Nov 10, 2026
Merged via the queue into main with commit 652da88 Nov 10, 2026
11 checks passed
@kixelated
kixelated deleted the quest/m2/confidence/adapters-hostile-input branch November 11, 2026 21:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant