Skip to content

eth/protocols/eth, eth/protocols/snap: delayed p2p message decoding#33835

Merged
rjl493456442 merged 5 commits into
ethereum:masterfrom
fjl:eth-rawlist
Feb 15, 2026
Merged

eth/protocols/eth, eth/protocols/snap: delayed p2p message decoding#33835
rjl493456442 merged 5 commits into
ethereum:masterfrom
fjl:eth-rawlist

Conversation

@fjl
Copy link
Copy Markdown
Contributor

@fjl fjl commented Feb 13, 2026

This changes the p2p protocol handlers to delay message decoding. It's the first part of a larger change that will delay decoding all the way through message processing. For responses, we delay the decoding until it is confirmed that the response matches an active request and does not exceed its limits.

In order to make this work, all messages have been changed to use rlp.RawList instead of a slice of the decoded item type. For block bodies specifically, the decoding has been delayed all the way until after verification of the response hash.

The role of p2p/tracker.Tracker changes significantly in this PR. The Tracker's original purpose was to maintain metrics about requests and responses in the peer-to-peer protocols. Each protocol maintained a single global Tracker instance. As of this change, the Tracker is now always active (regardless of metrics collection), and there is a separate instance of it for each peer. Whenever a response arrives, it is first verified that a request exists for it in the tracker. The tracker is also the place where limits are kept.

rjl493456442
rjl493456442 previously approved these changes Feb 13, 2026
@fjl fjl force-pushed the eth-rawlist branch 2 times, most recently from 86aae79 to f9f0e90 Compare February 13, 2026 20:53
fjl added 5 commits February 13, 2026 23:54
This changes the p2p protocol handlers to delay message decoding. It's the first
part of a larger change that will delay decoding all the way through message
processing. For responses, we delay the decoding until it is confirmed that the
response matches an active request and does not exceed its limits.

In order to make this work, all messages have been changed to use rlp.RawList
instead of a slice of the decoded item type. For block bodies specifically, the
decoding has been delayed all the way until after verification of the response
hash.

The role of p2p/tracker.Tracker changes significantly in this PR. The Tracker's
original purpose was to maintain metrics about requests and responses in the
peer-to-peer protocols. Each protocol maintained a single global Tracker
instance. As of this change, the Tracker is now always active (regardless of
metrics collection), and there is a separate instance of it for each peer.
Whenever a response arrives, it is first verified that a request exists for it
in the tracker. The tracker is also the place where limits are kept.
@rjl493456442 rjl493456442 added this to the 1.17.0 milestone Feb 15, 2026
@rjl493456442 rjl493456442 merged commit 0cba803 into ethereum:master Feb 15, 2026
7 of 8 checks passed
chris-mercer added a commit to chris-mercer/core-geth that referenced this pull request Mar 21, 2026
A malicious peer can send a p2p response with a valid RLP list header
claiming millions of tiny items. The 10 MiB maxMessageSize check passes,
but msg.Decode allocates pointer/struct objects proportional to item count
before the response is validated, causing OOM.

This adds pre-decode item count validation for both eth and snap protocols.
Before msg.Decode runs, the raw message payload (already buffered by the
transport layer) is scanned using rlp.CountValues — a zero-allocation
operation that reads only RLP tag bytes. If the item count exceeds the
protocol limit, the message is rejected immediately.

Validated eth messages: BlockHeaders, BlockBodies, Receipts,
PooledTransactions, Transactions, NewBlockHashes.
Validated snap messages: AccountRange, StorageRanges, ByteCodes, TrieNodes.

Limits: 2048 for responses (2x serve-side maxHeadersServe/maxBodiesServe),
32768 for transaction broadcasts (matches maxKnownTxs).

This is a minimal port of upstream go-ethereum PR #33835. The full upstream
refactor (delayed message decoding with rlp.RawList) cannot be cleanly
backported due to structural divergence (13 merge conflicts).

References:
- CVE-2026-26313: GHSA-689v-6xwf-5jf3
- Upstream fix: ethereum/go-ethereum#33835
- Issue etclabscore#692: etclabscore#692

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
chris-mercer added a commit to chris-mercer/core-geth that referenced this pull request Mar 24, 2026
A malicious peer can send a p2p response with a valid RLP list header
claiming millions of tiny items. The 10 MiB maxMessageSize check passes,
but msg.Decode allocates pointer/struct objects proportional to item count
before the response is validated, causing OOM.

This adds pre-decode item count validation for both eth and snap protocols.
Before msg.Decode runs, the raw message payload (already buffered by the
transport layer) is scanned using rlp.CountValues — a zero-allocation
operation that reads only RLP tag bytes. If the item count exceeds the
protocol limit, the message is rejected immediately.

Validated eth messages: BlockHeaders, BlockBodies, Receipts,
PooledTransactions, Transactions, NewBlockHashes.
Validated snap messages: AccountRange, StorageRanges, ByteCodes, TrieNodes.

Limits: 2048 for responses (2x serve-side maxHeadersServe/maxBodiesServe),
32768 for transaction broadcasts (matches maxKnownTxs).

This is a minimal port of upstream go-ethereum PR #33835. The full upstream
refactor (delayed message decoding with rlp.RawList) cannot be cleanly
backported due to structural divergence (13 merge conflicts).

References:
- CVE-2026-26313: GHSA-689v-6xwf-5jf3
- Upstream fix: ethereum/go-ethereum#33835
- Issue etclabscore#692: etclabscore#692

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
sduchesneau pushed a commit to streamingfast/go-ethereum that referenced this pull request Apr 7, 2026
…thereum#33835)

This changes the p2p protocol handlers to delay message decoding. It's
the first part of a larger change that will delay decoding all the way
through message processing. For responses, we delay the decoding until
it is confirmed that the response matches an active request and does not
exceed its limits.

In order to make this work, all messages have been changed to use
rlp.RawList instead of a slice of the decoded item type. For block
bodies specifically, the decoding has been delayed all the way until
after verification of the response hash.

The role of p2p/tracker.Tracker changes significantly in this PR. The
Tracker's original purpose was to maintain metrics about requests and
responses in the peer-to-peer protocols. Each protocol maintained a
single global Tracker instance. As of this change, the Tracker is now
always active (regardless of metrics collection), and there is a
separate instance of it for each peer. Whenever a response arrives, it
is first verified that a request exists for it in the tracker. The
tracker is also the place where limits are kept.
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.

2 participants