Skip to content

fix(websocket): OOB read from oversized/wrapped frame length (#852) - #864

Merged
ithewei merged 1 commit into
masterfrom
fix/websocket-parser-oob
Aug 6, 2026
Merged

fix(websocket): OOB read from oversized/wrapped frame length (#852)#864
ithewei merged 1 commit into
masterfrom
fix/websocket-parser-oob

Conversation

@ithewei

@ithewei ithewei commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Fixes #852 — OOB read from an oversized / wrapped WebSocket frame length.

Root cause

http/websocket_parser.c (vendored) checked body availability with:

if (p + parser->require <= end)   // s_body

For a peer-declared 64-bit payload length (e.g. all 0xFF, which also has the MSB set that RFC 6455 §5.2 forbids), parser->require is ~SIZE_MAX, so p + parser->require overflows the pointer and wraps to a value ≤ end. The check passes and frame_body is emitted with length ≈ SIZE_MAX while only a few bytes are valid. WebSocketParser.cpp then trusts it:

websocket_parser_decode((char*)at, at, length, ...);  // in-place, huge length
wp->message.append(at, length);                        // OOB read

→ out-of-bounds read / crash for any peer that can send WebSocket frames.

Fix

  • websocket_parser.c: compare against the real remaining bytes, parser->require <= (size_t)(end - p), which cannot overflow.
  • WebSocketParser.cpp on_frame_header: stop truncating parser->length (size_t) to int; use it only as a capacity hint capped to MAX_PAYLOAD_LENGTH — never trust a peer-declared length for allocation. (Body bytes are still appended incrementally against real buffer data.)

Verified

  • Crafted frame 81 7F FF FF FF FF FF FF FF FF 41 (FIN+TEXT, 64-bit len all 0xFF, 1 payload byte):
    • before: on_frame_body length=18446744073709551615
    • after: on_frame_body length=1
  • Normal frames still parse: unmasked "hello", the same frame split across two execute() calls, and a 126/16-bit-length 200-byte frame — all OK.
  • make libhv + ws client/server examples build clean.

Reported by the issue author (with a minimal C-core repro); this patches the vendored parser and the product-specific amplification in the C++ wrapper.

Copilot AI lite review requested due to automatic review settings August 5, 2026 15:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…852)

The vendored websocket_parser.c body-availability check used
'p + parser->require <= end'. For a peer-declared 64-bit payload length
(e.g. all 0xFF, MSB set which RFC 6455 forbids), that pointer arithmetic
overflows and wraps below 'end', so the check passes and frame_body is
emitted with length ~= SIZE_MAX while only a few bytes are valid. The C++
wrapper then append()s / in-place decode()s that many bytes -> OOB read /
crash for any peer that can send WebSocket frames.

- websocket_parser.c: compare against real remaining bytes,
  'parser->require <= (size_t)(end - p)', which cannot overflow.
- WebSocketParser.cpp on_frame_header: stop truncating parser->length to
  int; use it only as a capacity hint capped to MAX_PAYLOAD_LENGTH (never
  trust a peer-declared length for allocation).

Verified: a crafted 0xFF-length frame now emits body length=1 (the real
available byte) instead of 0xFFFFFFFFFFFFFFFF; normal frames (unmasked,
split across execute() calls, 16-bit length) still parse correctly. Fixes #852.
Copilot AI review requested due to automatic review settings August 6, 2026 03:13
@ithewei
ithewei force-pushed the fix/websocket-parser-oob branch from 2e127db to 967cdf6 Compare August 6, 2026 03:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ithewei
ithewei merged commit 2bd2061 into master Aug 6, 2026
12 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.

WebSocketParser: oversized body length after pointer wrap in vendored websocket_parser (related php-ion#5)

2 participants