Skip to content

fix(net): refuse malformed complete announce bodies - #6909

Merged
kixelated merged 2 commits into
mainfrom
quest/m1/cut-audit/announce-decode-complete
Oct 27, 2026
Merged

kixelated merged 2 commits into
mainfrom
quest/m1/cut-audit/announce-decode-complete

Conversation

@kixelated

@kixelated kixelated commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

A complete size-prefixed ANNOUNCE body could return Short for a missing inner field. The stream reader then waited for bytes outside that body, leaving announce discovery stalled while the peer kept its stream open.

Approach

Apply the existing DecodeError::complete rule after both legacy and lite-06/07 bodies are fully buffered. The production announce subscriber now closes the session with PROTOCOL_VIOLATION; an incomplete outer frame still waits and resumes normally. Other lite/IETF bounded-body decoders already apply the rule.

Strengthen the private fuzz roundtrip invariant so Short must require more outer input. Register TRACKS, TRACKS_EVENT, AUTH, AUTH_OK, AUTH_ERROR, and AUTH_REPLY, with valid seeds and three ANNOUNCE counterexamples replayed in the normal suite.

Impact

  • Public API: none.
  • Wire: no encoding, version, or draft change. Existing malformed-message refusal applies immediately instead of waiting indefinitely.
  • Consumers: the lite announce subscriber and the existing stable/native wire-fuzz targets. No retry, sleep, deadline increase, or new byte cap.

Validation

  • Before the source fix, the real announce-stream state machine returned Pending for a complete malformed lite-05 body on an open peer stream. Its genuinely incomplete outer-frame control passed.
  • After the fix, lite-05/06/07 all record the actual transport PROTOCOL_VIOLATION close without waiting for FIN or more bytes. A split valid frame stays open and announces its route after the last byte arrives.
  • Stable fuzz corpus replay and every-arm valid-seed coverage pass, including all six added targets. The normal seed generator writes 26,587 inputs.
  • Clean committed-head nix develop --command just ci origin/main passes on 4a58bf37ab41dadd31a547dab95259369e72b259 against base f23b4107ba0a1e679cfa9b708239ed7b0e3ce86d: 1,224 seconds, 9,114 Rust tests passed (97 skipped), strict feature/transport checks, and repository tooling. Trusted quest check passes for 617 documents.
  • Native lite fuzz was attempted with cached cargo-fuzz 0.13.2 and nightly Rust 1.101.0 (2026-10-18), preserving the workflow's -D recursion_depth_exceeding_limit. The build stops before any fuzz executions at unchanged rs/moq-net/src/ietf/publisher/tracks.rs:826 (the Send/MaybeBoxedExt future chain). No recursion limit was raised or lint weakened.
  • just fix was run and stops at the unchanged rs/moq-mux/benches/catalog.rs:226 reference to missing hang::catalog::MAX_RENDITIONS. Changed Rust files were formatted independently.

Alternatives

Waiting for a later byte or FIN does not repair an already complete body. Applying completion only after the declared body arrives preserves legitimate streaming reads and uses the same boundary as other control messages.

Follow-ups

  • Native fuzz awaits the existing Send-proof work, tracked by quest/m0/nightly/send-overflow.md. The exact nightly build limitation is also recorded on moq-dev/moq#6648. The stable target replay and required full gate above are distinct passing evidence.
  • Repair the unrelated catalog benchmark constant independently, as reported on moq-dev/moq#6902 and moq-dev/moq#6907.
  • moq-dev/moq#6753 adds two SETUP fuzz registrations at the same dispatch tail. Preserve those and these six new registrations when integrating; no runtime decoder semantics overlap. Its draft removal has not landed in this PR's base.

(Written by GPT-6)

kixelated and others added 2 commits October 26, 2026 21:11
@kixelated kixelated changed the title A malformed lite message closes the session instead of jamming its stream fix(net): refuse malformed complete announce bodies Oct 27, 2026
@kixelated
kixelated marked this pull request as ready for review October 27, 2026 04:45
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T04:46:50.663314Z 4a58bf3 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: 4a58bf3

No actionable bugs found in the changed code and relevant surrounding paths. Applying DecodeError::complete only after sub(size) succeeds is the right boundary: malformed complete legacy and typed ANNOUNCE bodies become protocol violations, while genuinely incomplete outer frames still wait. Unknown-type skipping and trailing-byte rejection remain intact.

The small local closure follows the existing TRACKS decoder pattern; a broader framing refactor is not needed for this fix. The open-stream failure test, split-valid-frame control, corpus cases, and six additional fuzz dispatch arms provide focused regression coverage.

Verification: source inspection of decoding, reader retry/error propagation, subscriber state machine, test transport, and fuzz harness/seeds. I did not run builds, tests, or fuzzing; the PR's reported validation was not independently reproduced.

@coderabbitai

coderabbitai Bot commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
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: dbd733b0-08a0-4850-a0a4-efed6cb0f30a
Commits

Reviewing files that changed from the base of the PR and between f23b410 and 4a58bf3.

Files selected for processing: 9
  • quest/m1/cut-audit/README.md
  • quest/m1/cut-audit/announce-decode-complete.md
  • rs/moq-net/fuzz/README.md
  • rs/moq-net/fuzz/regressions/lite/complete-announce-lite05
  • rs/moq-net/fuzz/regressions/lite/complete-announce-lite06
  • rs/moq-net/fuzz/regressions/lite/complete-announce-lite07
  • rs/moq-net/src/fuzz.rs
  • rs/moq-net/src/lite/announce.rs
  • rs/moq-net/src/lite/subscriber.rs
Files with no reviewable changes: 2
  • quest/m1/cut-audit/README.md
  • quest/m1/cut-audit/announce-decode-complete.md

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 0 remain after this review.

Walkthrough

Lite ANNOUNCE body decoding now maps decode errors through DecodeError::complete for lite-06+ and legacy messages. Subscriber tests check malformed complete bodies and incomplete bodies. The fuzz harness adds six lite message kinds, incremental decode checks, two seeds, and a regression input. Fuzz guidance now distinguishes incomplete outer input from malformed fields inside a complete body.

Priority: Normal

Severity of issue fixed: Low

Merge Risk: Minimal · up to 4a58b

No merge-blocking issue is established. The change is mergeable after normal checks.

Pre-merge checks: Passed 5
Check name Status Explanation
Description check Passed The description clearly explains the malformed ANNOUNCE body fix, its implementation, validation, impact, and known unrelated limitations.
Title check Passed The title directly and concisely identifies the main change: refusing malformed complete ANNOUNCE bodies.
Docstring Coverage Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surviv…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 6 functions across 3 files. (2 skipped: 2 unsupported.)

Finishing Touches
✨ Simplify code
  • Commit to this branch
  • Create a new PR
  • 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

Comment @coderabbitai help to get the list of available commands.

@kixelated

Copy link
Copy Markdown
Collaborator Author

Merge summary for head 4a58bf37ab41dadd31a547dab95259369e72b259:

  • Reviews: Codex 👍 and CodeRabbit (no actionable comments) on this head; no unresolved threads. No code changes made during merge.
  • Local verification on the head merged with current main (88620648e0, merged locally only, not pushed; no conflicts): just check origin/main passed every selected lane (check/test rs with 9,120 tests passed, gh, markdown, shell, quest, drill, toml, nix, justfile, large_files). Trusted quest check passes on the head (617 documents).
  • just test interop --all: the first run failed only go -> c with "audio gap" (an FFI publisher tone gap tracked by quest/m0/test-flakes-2/ffi-audio-gap.md, unrelated to ANNOUNCE decoding). The rerun passed all 173 checks.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 0036bbd Oct 27, 2026
13 checks passed
@kixelated
kixelated deleted the quest/m1/cut-audit/announce-decode-complete branch October 27, 2026 08:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant