From 9fc733c2e2c790f5e27e771b423697a975155a8c Mon Sep 17 00:00:00 2001 From: CPerezz Date: Thu, 9 Apr 2026 12:19:51 +0200 Subject: [PATCH] core/state,triedb/pathdb: add defensive length checks in encodeBinary and encodeStemBlob Addresses review findings I13 and S6. encodeBinary: reject non-nil bintrie leaves with length != 32 at the trust boundary between the hasher and the state update. Previously a wrong-length leaf silently made it into the diff layer's accountData and only surfaced as a panic deep in the Flush path (stemBuilder.set). encodeStemBlob: add an upper-bound check on the value count (must be <= 256, the maximum offsets per stem). Previously a buggy producer could pass an arbitrarily long values slice. --- core/state/stateupdate.go | 10 +++++++++- triedb/pathdb/stem_blob.go | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/core/state/stateupdate.go b/core/state/stateupdate.go index 44df4427df..342a80b73f 100644 --- a/core/state/stateupdate.go +++ b/core/state/stateupdate.go @@ -301,10 +301,18 @@ func (sc *stateUpdate) encodeBinary() (map[common.Hash][]byte, map[common.Addres accounts[fullKey] = nil continue } + // Defensive length check: every non-nil bintrie leaf must be + // exactly 32 bytes. A wrong-length leaf from the hasher would + // silently produce garbage in the diff layer; catch it here at + // the trust boundary rather than deep in the flush path where + // the stemBuilder.set panic would fire with less context. + if len(w.Value) != 32 { + return nil, nil, nil, nil, fmt.Errorf("bintrie leaf at stem %x offset %d has value len %d, want 32", w.Stem, w.Offset, len(w.Value)) + } // Take an owning copy: the hasher reuses its underlying buffers // across blocks, so retaining its slices would create cross-block // aliasing bugs in the pathdb diff layer. - v := make([]byte, len(w.Value)) + v := make([]byte, 32) copy(v, w.Value) accounts[fullKey] = v } diff --git a/triedb/pathdb/stem_blob.go b/triedb/pathdb/stem_blob.go index fce8be98ae..5ec731b95f 100644 --- a/triedb/pathdb/stem_blob.go +++ b/triedb/pathdb/stem_blob.go @@ -84,6 +84,9 @@ func encodeStemBlob(bitmap [stemBlobBitmapSize]byte, values [][]byte) ([]byte, e if count != len(values) { return nil, fmt.Errorf("stem blob popcount=%d values=%d: %w", count, len(values), errStemBlobMalformed) } + if count > stemBlobBitmapBits { + return nil, fmt.Errorf("stem blob value count %d exceeds max %d: %w", count, stemBlobBitmapBits, errStemBlobMalformed) + } if count == 0 { return nil, nil }