Skip to content

Commit 6cfd717

Browse files
authored
Merge pull request #2558 from starius/trailing
multi: reject trailing characters when parsing inputs
2 parents 280d4d2 + 934349f commit 6cfd717

18 files changed

Lines changed: 639 additions & 37 deletions

blockchain/chainio.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,8 +1277,7 @@ func (b *BlockChain) initChainState() error {
12771277
if err != nil {
12781278
return err
12791279
}
1280-
var block wire.MsgBlock
1281-
err = block.Deserialize(bytes.NewReader(blockBytes))
1280+
block, err := btcutil.NewBlockFromBytes(blockBytes)
12821281
if err != nil {
12831282
return err
12841283
}
@@ -1304,8 +1303,8 @@ func (b *BlockChain) initChainState() error {
13041303

13051304
// Initialize the state related to the best block.
13061305
blockSize := uint64(len(blockBytes))
1307-
blockWeight := uint64(GetBlockWeight(btcutil.NewBlock(&block)))
1308-
numTxns := uint64(len(block.Transactions))
1306+
blockWeight := uint64(GetBlockWeight(block))
1307+
numTxns := uint64(len(block.MsgBlock().Transactions))
13091308
b.stateSnapshot = newBestState(tip, blockSize, blockWeight,
13101309
numTxns, state.totalTxns, CalcPastMedianTime(tip))
13111310

blockchain/chainio_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ import (
99
"errors"
1010
"math/big"
1111
"reflect"
12+
"strings"
1213
"testing"
1314

15+
"github.com/btcsuite/btcd/btcutil/v2"
1416
"github.com/btcsuite/btcd/database"
17+
"github.com/btcsuite/btcd/txscript/v2"
1518
"github.com/btcsuite/btcd/wire/v2"
1619
)
1720

@@ -37,6 +40,52 @@ func TestErrNotInMainChain(t *testing.T) {
3740
}
3841
}
3942

43+
// TestInitChainStateRejectsTrailingBestBlockBytes ensures startup rejects a
44+
// stored best block whose bytes contain a valid block plus trailing data.
45+
func TestInitChainStateRejectsTrailingBestBlockBytes(t *testing.T) {
46+
chain, params, teardown := utxoCacheTestChain(
47+
"TestInitChainStateRejectsTrailingBestBlockBytes")
48+
defer teardown()
49+
50+
tip := btcutil.NewBlock(params.GenesisBlock)
51+
tip.SetHeight(0)
52+
53+
block, _, err := newBlock(chain, tip, nil)
54+
if err != nil {
55+
t.Fatalf("failed to build block: %v", err)
56+
}
57+
58+
var serialized bytes.Buffer
59+
err = block.MsgBlock().Serialize(&serialized)
60+
if err != nil {
61+
t.Fatalf("failed to serialize block: %v", err)
62+
}
63+
64+
trailingBytes := append([]byte(nil), serialized.Bytes()...)
65+
trailingBytes = append(trailingBytes, 0x00)
66+
trailingBlock := btcutil.NewBlockFromBlockAndBytes(
67+
block.MsgBlock(), trailingBytes,
68+
)
69+
70+
_, _, err = chain.ProcessBlock(trailingBlock, BFNone)
71+
if err != nil {
72+
t.Fatalf("failed to process block: %v", err)
73+
}
74+
75+
_, err = New(&Config{
76+
DB: chain.db,
77+
ChainParams: params,
78+
TimeSource: NewMedianTime(),
79+
SigCache: txscript.NewSigCache(1000),
80+
})
81+
if err == nil {
82+
t.Fatal("expected trailing best block bytes to fail startup")
83+
}
84+
if !strings.Contains(err.Error(), "trailing bytes") {
85+
t.Fatalf("expected trailing byte error, got: %v", err)
86+
}
87+
}
88+
4089
// TestStxoSerialization ensures serializing and deserializing spent transaction
4190
// output entries works as expected.
4291
func TestStxoSerialization(t *testing.T) {

btcec/schnorr/musig2/sign.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func (p *PartialSignature) Decode(r io.Reader) error {
9191

9292
var sBytes [32]byte
9393
if _, err := io.ReadFull(r, sBytes[:]); err != nil {
94-
return nil
94+
return err
9595
}
9696

9797
overflows := p.S.SetBytes(&sBytes)

btcec/schnorr/musig2/sign_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,27 @@ func pSigsFromIndices(t *testing.T, sigs []string, indices []int) []*PartialSign
311311
return pSigs
312312
}
313313

314+
// TestPartialSignatureDecodeRejectsShortReads verifies that Decode rejects
315+
// inputs that do not contain a full scalar.
316+
func TestPartialSignatureDecodeRejectsShortReads(t *testing.T) {
317+
t.Parallel()
318+
319+
testCases := map[string][]byte{
320+
"empty": nil,
321+
"truncated": bytes.Repeat([]byte{0x01}, 31),
322+
}
323+
324+
for name, testCase := range testCases {
325+
t.Run(name, func(t *testing.T) {
326+
t.Parallel()
327+
328+
var sig PartialSignature
329+
err := sig.Decode(bytes.NewReader(testCase))
330+
require.Error(t, err)
331+
})
332+
}
333+
}
334+
314335
// TestMusig2SignCombine tests that we pass the musig2 sig combination tests.
315336
func TestMusig2SignCombine(t *testing.T) {
316337
t.Parallel()

btcutil/block.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ func NewBlockFromBytes(serializedBlock []byte) (*Block, error) {
253253
if err != nil {
254254
return nil, err
255255
}
256+
if br.Len() > 0 {
257+
return nil, fmt.Errorf("block has %d trailing bytes", br.Len())
258+
}
256259
b.serializedBlock = serializedBlock
257260

258261
// This initializes []btcutil.Tx to have the serialized raw

btcutil/block_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,23 @@ func TestNewBlockFromBytes(t *testing.T) {
200200
}
201201
}
202202

203+
// TestNewBlockFromBytesRejectsTrailingData verifies that NewBlockFromBytes
204+
// rejects bytes after the serialized block.
205+
func TestNewBlockFromBytesRejectsTrailingData(t *testing.T) {
206+
var block100000Buf bytes.Buffer
207+
err := Block100000.Serialize(&block100000Buf)
208+
if err != nil {
209+
t.Errorf("Serialize: %v", err)
210+
}
211+
212+
_, err = btcutil.NewBlockFromBytes(
213+
append(block100000Buf.Bytes(), 0x00),
214+
)
215+
if err == nil {
216+
t.Fatal("expected error for block with trailing data")
217+
}
218+
}
219+
203220
// TestNewBlockFromBlockAndBytes tests creation of a Block from a MsgBlock and
204221
// raw bytes.
205222
func TestNewBlockFromBlockAndBytes(t *testing.T) {

btcutil/bloom/filter_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ func TestFilterBloomMatch(t *testing.T) {
325325
0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14,
326326
0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51,
327327
0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70,
328-
0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}
328+
0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00}
329329

330330
spendingTx, err := btcutil.NewTxFromBytes(spendingTxBytes)
331331
if err != nil {

btcutil/tx.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package btcutil
66

77
import (
88
"bytes"
9+
"fmt"
910
"io"
1011

1112
"github.com/btcsuite/btcd/chainhash/v2"
@@ -173,7 +174,16 @@ func (t *Tx) setBytes(bytes []byte) {
173174
// serialized bytes. See Tx.
174175
func NewTxFromBytes(serializedTx []byte) (*Tx, error) {
175176
br := bytes.NewReader(serializedTx)
176-
return NewTxFromReader(br)
177+
tx, err := NewTxFromReader(br)
178+
if err != nil {
179+
return nil, err
180+
}
181+
if br.Len() > 0 {
182+
return nil, fmt.Errorf("transaction has %d trailing bytes",
183+
br.Len())
184+
}
185+
186+
return tx, nil
177187
}
178188

179189
// NewTxFromReader returns a new instance of a bitcoin transaction given a

btcutil/tx_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,22 @@ func TestNewTxFromBytes(t *testing.T) {
7676
}
7777
}
7878

79+
// TestNewTxFromBytesRejectsTrailingData verifies that NewTxFromBytes rejects
80+
// bytes after the serialized transaction.
81+
func TestNewTxFromBytesRejectsTrailingData(t *testing.T) {
82+
testTx := Block100000.Transactions[0]
83+
var testTxBuf bytes.Buffer
84+
err := testTx.Serialize(&testTxBuf)
85+
if err != nil {
86+
t.Errorf("Serialize: %v", err)
87+
}
88+
89+
_, err = btcutil.NewTxFromBytes(append(testTxBuf.Bytes(), 0x00))
90+
if err == nil {
91+
t.Fatal("expected error for transaction with trailing data")
92+
}
93+
}
94+
7995
// TestTxErrors tests the error paths for the Tx API.
8096
func TestTxErrors(t *testing.T) {
8197
// Serialize the test transaction.

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ require (
3939
gopkg.in/yaml.v3 v3.0.1 // indirect
4040
)
4141

42+
replace (
43+
github.com/btcsuite/btcd/btcutil/v2 => ./btcutil
44+
github.com/btcsuite/btcd/wire/v2 => ./wire
45+
)
46+
4247
// The retract statements below fixes an accidental push of the tags of a btcd
4348
// fork.
4449
retract (

0 commit comments

Comments
 (0)