fix(moq-transport): reject present-but-zero subgroup history window - #67
Open
allyblockcast[bot] wants to merge 1 commit into
Open
fix(moq-transport): reject present-but-zero subgroup history window#67allyblockcast[bot] wants to merge 1 commit into
allyblockcast[bot] wants to merge 1 commit into
Conversation
A SUBSCRIBE_OK carrying key 0x40 with value 0 was mapped to None by `.and_then(NonZeroU64::new)` — the same result as the key being absent — so a malformed frame silently widened the mirror's retention to unbounded. That is a silent fallback on fork-added code, which the engineering principles ban. Reject it as a protocol violation instead. The two cases are not the same and only one has an interop defence: - absent 0x40 → a conforming generic peer that never implemented this private Blockcast extension. Omission is exactly how such a peer signals "unsupported", so leniency here is required and is UNCHANGED by this commit. Mandatory presence is negotiated by the Blockcast wire profile (BLO-22244), not enforced here. - present 0x40 = 0 → the peer implemented the extension and sent a meaningless value. A window of 0 groups retains nothing, so it cannot be what any publisher meant, and no conforming-peer reading applies. Gated on the sender inventory required by the MRS-02 G0 record (pim-multicast-gateway docs/g0/blo-22245-sender-inventory.md): key 0x40 has exactly one emission site in fork history, and at every commit that has ever touched it the value is `NonZeroU64::get()` — so no build of this fork, past or present, can emit 0. The other MoQ implementations we deploy (moq-lite, the hang-mmt-fec JS publisher) hardcode their param sets and cannot emit 0x40 at all. `recv_subscribe_ok_zero_window_is_unbounded` is replaced by `recv_subscribe_ok_zero_window_is_rejected`, asserting the protocol error. `recv_subscribe_ok_absent_window_is_unbounded` passes UNCHANGED — that is the assertion that the generic interop path was not disturbed. A non-integer value for this key is left as-is: it is malformed too, but the inventory gating this change covers the zero case, and widening scope silently is the habit this issue exists to break. Refs BLO-22245, BLO-21206 (MRS-02) Co-Authored-By: Claude <noreply@anthropic.com>
Author
1 similar comment
Author
Author
|
@ally please review at head 604a749 — this rejects a present-but-zero subgroup history window (key 0x40) in Review focus, in priority order:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the separable half of MRS-02 per the CTO ruling on BLO-21206. Tracked as BLO-22245.
The bug
recv_subscribe_okended with.and_then(NonZeroU64::new), which collapsed two different wire conditions to the same result:0x40absentNone→ unbounded0x40present,0None→ unboundedThe second case is the problem. The peer did implement the extension and sent a meaningless value — a window of 0 groups retains nothing, so it cannot be what any publisher meant. Reinterpreting it as "retain everything" widens retention on the strength of a frame we have just established is broken, on our own fork-added code where no conforming-peer defence applies. That is precisely the silent fallback the engineering principles ban.
What changed
Present-and-zero is now
SessionError::ProtocolViolation(MoQT error code0x3), propagating out of the control-message loop and terminating the session — the same teardown path as the siblingProtocolViolationreturns already in that loop.The absent path is untouched. It still yields unbounded with no error, and it stays profile-independent: requiring the key is BLO-22244's negotiated wire profile, and this PR deliberately introduces no mandatory-presence enforcement.
Gate: the sender inventory
This change was not allowed to land until a written sender inventory proved no deployed producer emits zero — the G0 record's own precondition. That inventory is pim-multicast-gateway#2079 (
docs/g0/blo-22245-sender-inventory.md). Summary:0x40has exactly one emission site in the whole fork, and at every commit that has ever touched it the value isNonZeroU64::get()— so no build of this fork, past or present or from any branch, can emit0. Guarded twice more upstream:TrackWriter::set_history_windowtakesNonZeroU64, and the remainingu64setter rejects0with a pinned test.moq-pub-mmtpuses a fixedPUBLISHER_HISTORY_WINDOW = 32, no override.moq-lite(incast) and the hang-mmt-fec JS publisher — hardcode theirSUBSCRIBE_OKparam sets and cannot emit0x40at all.Worth knowing if you re-derive this: the workspace moq-rs clone is shallow (depth 5), and
git log -Sover it names the wrong introducing commit. The inventory records that trap and one other; both failed in the permissive direction.Verification
recv_subscribe_ok_absent_window_is_unboundedpassing unchanged is the assertion that the generic interop path was not disturbed — that is the point of the test, not an incidental pass.Two things a reviewer should push on
0x40is deliberately left asNone. It is malformed too, and leaving it is arguably incoherent next to rejecting zero. I kept it out because the inventory gating this change covers the zero case, and quietly widening scope past the evidence is the habit this issue exists to break. Happy to take it in a follow-up with its own reasoning — say the word and I will file it.SUBSCRIBE_OKstill leaves its track alias bound intrack_alias_map, since the alias is inserted before the window is parsed. Harmless today because the session is torn down onProtocolViolation, but it is real state left behind and I would rather flag it than have it found later.Refs BLO-22245, BLO-21206 (MRS-02).
🤖 Generated with Claude Code