fix(p2p): reject reqresp requests larger than a single muxer frame#24554
Open
spalladino wants to merge 2 commits into
Open
fix(p2p): reject reqresp requests larger than a single muxer frame#24554spalladino wants to merge 2 commits into
spalladino wants to merge 2 commits into
Conversation
A reqresp request payload must arrive at the responder in a single chunk: yamux splits writes larger than one frame (64KiB including the 12-byte header) into multiple frames, and the responder never reassembles them into one request. Assert the size at the sender before dialing, so an oversized request type fails loudly locally instead of surfacing as a decoding error on the responder. Pin the yamux maxMessageSize to its library default so an upgrade cannot silently change the limit.
Collaborator
Flakey Tests🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry. |
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.
A reqresp request payload must fit in a single muxer frame: yamux splits writes larger than 64KiB (minus the 12-byte frame header) into multiple frames, each of which arrives at the responder as a separate chunk, and the responder never reassembles a request from multiple chunks. A request type growing past that limit would surface as a confusing decoding error on the responder instead of failing at the sender.
sendRequestToPeerbefore dialing, throwing a descriptiveOversizedReqRespRequestErrorlocally. The check runs before the generic error handling so the remote peer is not penalized for a local bug.maxMessageSizeon the yamux muxer to its library default (64KiB) so a dependency upgrade cannot silently change the limit the assertion relies on.Related to #24552.
No current subprotocol can exceed the limit
The limit is 65,524 bytes (64KiB yamux frame minus the 12-byte header). No reqresp subprotocol today can produce a request anywhere near it, so this assertion cannot fire on legitimate traffic:
GOODBYE: 1 byte (the reason code).PING: a few bytes.STATUS: aStatusMessage(component versions string, block numbers, block hash) — tens of bytes.AUTH: anAuthRequest(StatusMessageplus a 32-byte challenge) — tens of bytes.TX: the request type isTxHashArray(4 + 32·n bytes), but this subprotocol currently has no sender — only the server-side handler remains.BLOCK_TXS: the only request that scales with anything. Serialized asarchiveRoot(32 bytes) + tx-indicesBitVector(4 + ⌈N/8⌉ bytes, N = tx count of the proposal) + tx-hashes commitment (32 bytes) + optional full-hash vector (4 + 32·H bytes). Pinned-peer and smart-peer requests send indices only (H = 0). Dumb-peer requests include full hashes but chunk them totxBatchSize, which is always the default 8 in production (BatchTxRequesteris constructed without opts, and the option is not wired to any config). N is capped at deserialization byMAX_TXS_PER_BLOCK = 2^16, so even a maliciously large proposal yields a worst-case request of ~8.5KB — about 13% of the limit. A realistic 32-tx block produces requests of a few hundred bytes.Breaching the limit would take a proposal with ~460k txs (which
BitVector.fromBufferrejects at 2^16 anyway) or atxBatchSizeover ~1,800 with full hashes enabled — neither is reachable today. The assertion exists so that if a future change makes a request type scale past the limit, it fails loudly at the sender instead of as a decoding error at the responder.