Skip to content

fix(message,session): reject invalid FETCH Serialization Flags before reading fields (§11.4.4) - #112

Merged
floatdrop merged 1 commit into
draft-20from
draft20-fetch-flags
Sep 27, 2026
Merged

floatdrop merged 1 commit into
draft-20from
draft20-fetch-flags

Conversation

@floatdrop

Copy link
Copy Markdown
Owner

Finishes the last "protocol violations that MUST close the session" item in the draft-20 compliance backlog.

§11.4.4: "When less than 128, the bits represent flags ... [0x8C, 0x10C, 0x20C] ... Any other value is a PROTOCOL_VIOLATION."

Before this change, FetchObject.Parse read the fields that the bits of a flags value ≥ 128 selected, and only Validate rejected the value afterwards. If a stream reset or an oversized Payload Length followed such a value, the read failed with an ordinary error and the session stayed open.

Change

  • Parse checks the flags right after reading them, and returns the new message.ErrInvalidFetchFlags before touching any field.
  • IncomingFetchStream.ReadObject maps that error to PROTOCOL_VIOLATION. Its separate Validate call is gone, since Parse now covers it.
  • Validate shares the same check.
  • The item is removed from the STATUS.md backlog.

API: new exported message.ErrInvalidFetchFlags.

Tests

  • TestFetchObjectInvalidFlagsCloseSession now has three cases: invalid flags followed by a whole object, by a stream reset, and by an oversized Payload Length. The reset and oversized-length cases fail on the unpatched tree.
  • TestFetchObjectParseRejectsInvalidFlags fails when the early check is removed.
  • make bench-quick shows no change in allocs/op.

Unrelated, seen while testing

TestSubscribeTracks_ForwardsTrackGainedBySubscribe (relay) failed once during a full go test ./... run. The relay forwarded a PUBLISH to the subscriber whose own SUBSCRIBE created the track. It did not reproduce in 30 isolated runs or in 6 package runs, on either this branch or draft-20, and this PR doesn't touch the relay. It looks like a pre-existing race under load and is worth a separate look.

Test plan

  • go test ./...
  • go test -race ./pkg/moqt/...
  • golangci-lint run ./...
  • CI

🤖 Generated with Claude Code

… reading fields (§11.4.4)

"When less than 128, the bits represent flags ... Any other value is a
PROTOCOL_VIOLATION." FetchObject.Parse read the fields that the bits of
a value of 128 or more selected, and only Validate rejected it
afterwards. If a stream reset or an oversized Payload Length followed
such a value, the read failed with an ordinary error and the session
stayed open.

Parse now decides on the flags alone, right after reading them, and
returns the new message.ErrInvalidFetchFlags.
IncomingFetchStream.ReadObject maps that to PROTOCOL_VIOLATION; its
separate Validate call is gone, since Parse now covers it. Validate
shares the same check.

Verified red first: in TestFetchObjectInvalidFlagsCloseSession, the
reset and oversized-length cases on the unpatched tree; and
TestFetchObjectParseRejectsInvalidFlags against a mutant without the
early check. Allocs unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@floatdrop
floatdrop merged commit 7cf6cfc into draft-20 Sep 27, 2026
11 checks passed
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