From 4e608c115fd141c12439c7706ee1120ebbc5fa4f Mon Sep 17 00:00:00 2001 From: "Owain G. Ainsworth" Date: Wed, 9 Oct 2013 23:59:23 +0100 Subject: [PATCH] Prevent asInt() from modifying stack data. The stack data is normally sliced from the actual script and btcscript is not supposed to ever change the tx passed into it. Add a test (and fix the other leading zeros tests) to stop this happening again. --- stack.go | 12 +++++++++--- stack_test.go | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/stack.go b/stack.go index ae00f647..2a1cc556 100644 --- a/stack.go +++ b/stack.go @@ -19,10 +19,11 @@ func asInt(v []byte) *big.Int { if msb&0x80 == 0x80 { negative = true // remove sign bit - v[len(v)-1] &= 0x7f + msb &= 0x7f } + start := 0 // trim leading 0 bytes - for ; msb == 0; msb = v[len(v)-1] { + for ; msb == 0; msb, start = v[len(v)-1], start+1 { v = v[:len(v)-1] if len(v) == 0 { break @@ -31,7 +32,12 @@ func asInt(v []byte) *big.Int { // reverse bytes with a copy since stack is immutable. intArray := make([]byte, len(v)) for i := range v { - intArray[len(v)-i-1] = v[i] + // Mask off the sign bit without changing original array. + if i == 0 && start == 0 && negative { + intArray[len(v)-i -1] = v[i] & 0x7f + } else { + intArray[len(v)-i-1] = v[i] + } } num := new(big.Int).SetBytes(intArray) diff --git a/stack_test.go b/stack_test.go index f6c6e77c..19166aaf 100644 --- a/stack_test.go +++ b/stack_test.go @@ -8,6 +8,7 @@ import ( "bytes" "errors" "github.com/conformal/btcscript" + "fmt" "math/big" "testing" ) @@ -220,13 +221,14 @@ var stackTests = []stackTest{ }, { "popInt 1 leading 0", - [][]byte{{0x00000001}}, + [][]byte{{0x01, 0x00, 0x00, 0x00}}, func(stack *btcscript.Stack) error { v, err := stack.PopInt() if err != nil { return err } if v.Cmp(big.NewInt(1)) != 0 { + fmt.Printf("%v != %v\n", v, big.NewInt(1)) return errors.New("1 != 1 on popInt") } return nil @@ -234,6 +236,41 @@ var stackTests = []stackTest{ nil, [][]byte{}, }, + { + "popInt -1 leading 0", + [][]byte{{0x01,0x00, 0x00, 0x80}}, + func(stack *btcscript.Stack) error { + v, err := stack.PopInt() + if err != nil { + return err + } + if v.Cmp(big.NewInt(-1)) != 0 { + fmt.Printf("%v != %v\n", v, big.NewInt(-1)) + return errors.New("-1 != -1 on popInt") + } + return nil + }, + nil, + [][]byte{}, + }, + // Confirm that the asInt code doesn't modify the base data. + { + "peekint nomodify -1", + [][]byte{{0x01,0x00, 0x00, 0x80}}, + func(stack *btcscript.Stack) error { + v, err := stack.PeekInt(0) + if err != nil { + return err + } + if v.Cmp(big.NewInt(-1)) != 0 { + fmt.Printf("%v != %v\n", v, big.NewInt(-1)) + return errors.New("-1 != -1 on popInt") + } + return nil + }, + nil, + [][]byte{{0x01,0x00, 0x00, 0x80}}, + }, { "PushInt 0", [][]byte{},