Skip to content

fix(sender): fail fast on corrupt packet lengths and skip unknown packet types#129

Open
jasontitus wants to merge 3 commits into
swellweb:3.1-maintfrom
jasontitus:fix/protocol-drain-hardening
Open

fix(sender): fail fast on corrupt packet lengths and skip unknown packet types#129
jasontitus wants to merge 3 commits into
swellweb:3.1-maintfrom
jasontitus:fix/protocol-drain-hardening

Conversation

@jasontitus

Copy link
Copy Markdown

Stacked on #127 — includes its commits; review the last commit only.

Motivation

Two drain-loop weaknesses in TBMonitorProtocol.drainPacket, both mismatches with the receiver's C parser (which caps packets at 64 MiB and treats a bad length as fatal):

  1. A corrupted 4-byte length prefix (e.g. 0xFFFFFFFF) made the sender buffer inbound bytes forever, waiting for a packet that can never complete — unbounded memory growth on a corrupt stream.
  2. A packet with an unrecognized type byte (e.g. from a newer receiver) was consumed but reported as "buffer empty", stalling every valid packet queued behind it until the next network read — a forward-compatibility hazard for input relay.

What's in it

  • drainPacket now throws on a zero or >64 MiB length (maxPacketLength, mirroring net.c); the drain loop in TBDisplaySenderService closes the connection and surfaces the reason in the session status.
  • Unknown packet types are skipped and draining continues with the next packet.
  • 7 new unit tests: zero/oversized/all-ones lengths, the cap boundary (legal length still waiting for payload), corruption behind a valid packet, unknown-type skip, and lone unknown-type consumption.

How tested

xcodebuild test — 56/56 green (49 from #127 + 7 new).

🤖 Generated with Claude Code

jasontitus and others added 3 commits July 1, 2026 23:11
…ion parsing

Adds a TBDisplaySenderTests unit bundle (hosted by the app for @testable
access) with 49 tests over the pure logic that has no hardware dependency:

- TBMonitorProtocol: BE32 primitives, packet layout, drainPacket handling of
  fragmented/contiguous/split feeds, JSON payload round-trips, and parity of
  the hand-rolled input-event encoder with JSONDecoder — guarding the
  invariant documented on makeInputEventPacket (PR swellweb#123).
- TBDiscoveredReceiver: per-transport ip(for:) selection (which IP the sender
  dials for Thunderbolt vs Network Link), id, shortHostName, displayText.
- TBSenderAutomation: parseTransport/parseMode/parsePreset aliases,
  receiver matching, and the resolveSessionIndex tri-state.

The automation parsing helpers move from private to internal so the test
bundle can exercise them; behavior is unchanged. project.pbxproj and the
shared TBDisplaySender scheme are regenerated via xcodegen so a fresh
checkout can run `xcodebuild test` directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Executes the new TBDisplaySenderTests suite after the sender build.
- Triggers CI on 3.1-maint and 3.2-dev in addition to main, so the
  branches that actually receive PRs get build/test coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ket types

Two wire-protocol drain hardenings in TBMonitorProtocol.drainPacket, matching
the receiver parser's behavior (net.c caps packets at 64 MiB and treats a bad
length as fatal):

- A corrupt length prefix (zero, or above the new 64 MiB maxPacketLength) now
  throws instead of returning "need more data". Previously a corrupted length
  such as 0xFFFFFFFF made the sender buffer inbound bytes forever, waiting for
  a packet that could never complete — unbounded memory growth on a corrupt
  stream. The drain loop in TBDisplaySenderService now closes the connection
  and surfaces the reason in the session status.

- A packet with an unrecognized type byte (e.g. from a newer receiver) is now
  skipped and draining continues. Previously it consumed the packet but
  returned nil, which the caller treated as "buffer empty" — stalling every
  valid packet queued behind the unknown one until the next network read.

Covered by 7 new unit tests (zero/oversized/all-ones lengths, cap boundary,
corruption behind a valid packet, unknown-type skip and lone unknown-type).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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