mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-23 03:38:35 +00:00
vm: protect PUSHDATA from short reads
Same thing done in a2a8981979
for PUSHBYTES,
failing to read the amount of bytes specified should lead to FAULT. Also
makes readUint16() and readUint32() panic as this is the behavior we want in
these cases. Add some tests along the way.
This commit is contained in:
parent
14c02cb3b1
commit
fc1075bf75
3 changed files with 87 additions and 7 deletions
|
@ -89,7 +89,7 @@ func (c *Context) String() string {
|
|||
func (c *Context) readUint32() uint32 {
|
||||
start, end := c.IP(), c.IP()+4
|
||||
if end > len(c.prog) {
|
||||
return 0
|
||||
panic("failed to read uint32 parameter")
|
||||
}
|
||||
val := binary.LittleEndian.Uint32(c.prog[start:end])
|
||||
c.ip += 4
|
||||
|
@ -99,7 +99,7 @@ func (c *Context) readUint32() uint32 {
|
|||
func (c *Context) readUint16() uint16 {
|
||||
start, end := c.IP(), c.IP()+2
|
||||
if end > len(c.prog) {
|
||||
return 0
|
||||
panic("failed to read uint16 parameter")
|
||||
}
|
||||
val := binary.LittleEndian.Uint16(c.prog[start:end])
|
||||
c.ip += 2
|
||||
|
|
|
@ -262,16 +262,25 @@ func (v *VM) execute(ctx *Context, op Instruction) {
|
|||
case PUSHDATA1:
|
||||
n := ctx.readByte()
|
||||
b := ctx.readBytes(int(n))
|
||||
if b == nil {
|
||||
panic("failed to read instruction parameter")
|
||||
}
|
||||
v.estack.PushVal(b)
|
||||
|
||||
case PUSHDATA2:
|
||||
n := ctx.readUint16()
|
||||
b := ctx.readBytes(int(n))
|
||||
if b == nil {
|
||||
panic("failed to read instruction parameter")
|
||||
}
|
||||
v.estack.PushVal(b)
|
||||
|
||||
case PUSHDATA4:
|
||||
n := ctx.readUint32()
|
||||
b := ctx.readBytes(int(n))
|
||||
if b == nil {
|
||||
panic("failed to read instruction parameter")
|
||||
}
|
||||
v.estack.PushVal(b)
|
||||
|
||||
// Stack operations.
|
||||
|
|
|
@ -99,16 +99,87 @@ func TestPushm1to16(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPushData1(t *testing.T) {
|
||||
|
||||
func TestPushData1BadNoN(t *testing.T) {
|
||||
prog := []byte{byte(PUSHDATA1)}
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||
}
|
||||
|
||||
func TestPushData2(t *testing.T) {
|
||||
|
||||
func TestPushData1BadN(t *testing.T) {
|
||||
prog := []byte{byte(PUSHDATA1), 1}
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||
}
|
||||
|
||||
func TestPushData4(t *testing.T) {
|
||||
func TestPushData1Good(t *testing.T) {
|
||||
prog := makeProgram(PUSHDATA1, 3, 1, 2, 3)
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||
assert.Equal(t, 1, vm.estack.Len())
|
||||
assert.Equal(t, []byte{1, 2, 3}, vm.estack.Pop().Bytes())
|
||||
}
|
||||
|
||||
func TestPushData2BadNoN(t *testing.T) {
|
||||
prog := []byte{byte(PUSHDATA2)}
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||
}
|
||||
|
||||
func TestPushData2ShortN(t *testing.T) {
|
||||
prog := []byte{byte(PUSHDATA2), 0}
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||
}
|
||||
|
||||
func TestPushData2BadN(t *testing.T) {
|
||||
prog := []byte{byte(PUSHDATA2), 1, 0}
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||
}
|
||||
|
||||
func TestPushData2Good(t *testing.T) {
|
||||
prog := makeProgram(PUSHDATA2, 3, 0, 1, 2, 3)
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||
assert.Equal(t, 1, vm.estack.Len())
|
||||
assert.Equal(t, []byte{1, 2, 3}, vm.estack.Pop().Bytes())
|
||||
}
|
||||
|
||||
func TestPushData4BadNoN(t *testing.T) {
|
||||
prog := []byte{byte(PUSHDATA4)}
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||
}
|
||||
|
||||
func TestPushData4BadN(t *testing.T) {
|
||||
prog := []byte{byte(PUSHDATA4), 1, 0, 0, 0}
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||
}
|
||||
|
||||
func TestPushData4ShortN(t *testing.T) {
|
||||
prog := []byte{byte(PUSHDATA4), 0, 0, 0}
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
assert.Equal(t, true, vm.state.HasFlag(faultState))
|
||||
}
|
||||
|
||||
func TestPushData4Good(t *testing.T) {
|
||||
prog := makeProgram(PUSHDATA4, 3, 0, 0, 0, 1, 2, 3)
|
||||
vm := load(prog)
|
||||
vm.Run()
|
||||
assert.Equal(t, false, vm.state.HasFlag(faultState))
|
||||
assert.Equal(t, 1, vm.estack.Len())
|
||||
assert.Equal(t, []byte{1, 2, 3}, vm.estack.Pop().Bytes())
|
||||
}
|
||||
|
||||
func TestNOTNoArgument(t *testing.T) {
|
||||
|
|
Loading…
Reference in a new issue