From 78ff9911c5fdc4f3f6c1cb71f3e59cda8c7fe098 Mon Sep 17 00:00:00 2001 From: jsvisa Date: Tue, 4 Nov 2025 17:15:50 +0800 Subject: [PATCH 1/4] triedb/pathdb: fix 32-bit integer overflow in history trienode decoder --- triedb/pathdb/history_trienode.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/triedb/pathdb/history_trienode.go b/triedb/pathdb/history_trienode.go index 3f45b41117d..761bde5c37d 100644 --- a/triedb/pathdb/history_trienode.go +++ b/triedb/pathdb/history_trienode.go @@ -19,6 +19,7 @@ package pathdb import ( "bytes" "encoding/binary" + "errors" "fmt" "iter" "maps" @@ -392,6 +393,12 @@ func decodeSingle(keySection []byte, onValue func([]byte, int, int) error) ([]st nValue, nn := binary.Uvarint(keySection[keyOff:]) // value length (varint) keyOff += nn + // Validate that the values can fit in an int to prevent overflow on 32-bit systems + const maxInt = int(^uint(0) >> 1) + if nShared > uint64(maxInt) || nUnshared > uint64(maxInt) || nValue > uint64(maxInt) { + return nil, errors.New("key size too large") + } + // Resolve unshared key if keyOff+int(nUnshared) > len(keySection) { return nil, fmt.Errorf("key length too long, unshared key length: %d, off: %d, section size: %d", nUnshared, keyOff, len(keySection)) From e71031e02f4b600f60389a580b3ffe5a46914245 Mon Sep 17 00:00:00 2001 From: jsvisa Date: Tue, 4 Nov 2025 18:00:16 +0800 Subject: [PATCH 2/4] triedb/pathdb: check result --- triedb/pathdb/history_trienode.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/triedb/pathdb/history_trienode.go b/triedb/pathdb/history_trienode.go index 761bde5c37d..6334633889b 100644 --- a/triedb/pathdb/history_trienode.go +++ b/triedb/pathdb/history_trienode.go @@ -387,10 +387,19 @@ func decodeSingle(keySection []byte, onValue func([]byte, int, int) error) ([]st } // Resolve the entry from key section nShared, nn := binary.Uvarint(keySection[keyOff:]) // key length shared (varint) + if nn <= 0 { + return nil, fmt.Errorf("corrupted varint encoding for nShared at offset %d", keyOff) + } keyOff += nn nUnshared, nn := binary.Uvarint(keySection[keyOff:]) // key length not shared (varint) + if nn <= 0 { + return nil, fmt.Errorf("corrupted varint encoding for nUnshared at offset %d", keyOff) + } keyOff += nn nValue, nn := binary.Uvarint(keySection[keyOff:]) // value length (varint) + if nn <= 0 { + return nil, fmt.Errorf("corrupted varint encoding for nValue at offset %d", keyOff) + } keyOff += nn // Validate that the values can fit in an int to prevent overflow on 32-bit systems From 26aa505581a5130116f8858e656a0d66d8872a2b Mon Sep 17 00:00:00 2001 From: jsvisa Date: Tue, 4 Nov 2025 18:00:53 +0800 Subject: [PATCH 3/4] triedb/pathdb: fill more chars --- triedb/pathdb/history_trienode_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/triedb/pathdb/history_trienode_test.go b/triedb/pathdb/history_trienode_test.go index d6b80f61f56..be4740a9045 100644 --- a/triedb/pathdb/history_trienode_test.go +++ b/triedb/pathdb/history_trienode_test.go @@ -694,7 +694,10 @@ func TestDecodeSingleCorruptedData(t *testing.T) { // Test with corrupted varint in key section corrupted := make([]byte, len(keySection)) copy(corrupted, keySection) - corrupted[5] = 0xFF // Corrupt varint + // Fill first 10 bytes with 0xFF to create a varint overflow (>64 bits) + for i := range 10 { + corrupted[i] = 0xFF + } _, err = decodeSingle(corrupted, nil) if err == nil { t.Fatal("Expected error for corrupted varint") From 9ab465ffc2e20297fa5916fcf1f4499d961799a3 Mon Sep 17 00:00:00 2001 From: jsvisa Date: Thu, 6 Nov 2025 18:59:29 +0800 Subject: [PATCH 4/4] triedb/pathdb: use math.MaxUint32 --- triedb/pathdb/history_trienode.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/triedb/pathdb/history_trienode.go b/triedb/pathdb/history_trienode.go index 6334633889b..1004106af9c 100644 --- a/triedb/pathdb/history_trienode.go +++ b/triedb/pathdb/history_trienode.go @@ -23,6 +23,7 @@ import ( "fmt" "iter" "maps" + "math" "slices" "sort" "time" @@ -403,8 +404,7 @@ func decodeSingle(keySection []byte, onValue func([]byte, int, int) error) ([]st keyOff += nn // Validate that the values can fit in an int to prevent overflow on 32-bit systems - const maxInt = int(^uint(0) >> 1) - if nShared > uint64(maxInt) || nUnshared > uint64(maxInt) || nValue > uint64(maxInt) { + if nShared > uint64(math.MaxUint32) || nUnshared > uint64(math.MaxUint32) || nValue > uint64(math.MaxUint32) { return nil, errors.New("key size too large") }