stackitem: add limit to serialized items

Standard binary serialization/deserialization is mostly used in VM to put/get
elements into/from storage, so they never should exceed MaxSize (otherwise one
won't be able to deserialize these items).

This patch leaves EncodeBinaryStackItem unprotected, but that's a streaming
interface, so it's up to the user of it to ensure its appropriate use (and our
uses are mostly for native contract's data, so they're fine).
This commit is contained in:
Roman Khimov 2021-07-06 19:34:02 +03:00
parent 8472064bbc
commit b9ff07f32c
2 changed files with 34 additions and 4 deletions

View file

@ -12,6 +12,7 @@ import (
// serContext is an internal serialization context. // serContext is an internal serialization context.
type serContext struct { type serContext struct {
*io.BinWriter *io.BinWriter
buf *io.BufBinWriter
allowInvalid bool allowInvalid bool
seen map[Item]bool seen map[Item]bool
} }
@ -21,6 +22,7 @@ func SerializeItem(item Item) ([]byte, error) {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
sc := serContext{ sc := serContext{
BinWriter: w.BinWriter, BinWriter: w.BinWriter,
buf: w,
allowInvalid: false, allowInvalid: false,
seen: make(map[Item]bool), seen: make(map[Item]bool),
} }
@ -49,6 +51,7 @@ func EncodeBinaryStackItemAppExec(item Item, w *io.BinWriter) {
bw := io.NewBufBinWriter() bw := io.NewBufBinWriter()
sc := serContext{ sc := serContext{
BinWriter: bw.BinWriter, BinWriter: bw.BinWriter,
buf: bw,
allowInvalid: true, allowInvalid: true,
seen: make(map[Item]bool), seen: make(map[Item]bool),
} }
@ -68,10 +71,6 @@ func (w *serContext) serialize(item Item) {
w.Err = errors.New("recursive structures can't be serialized") w.Err = errors.New("recursive structures can't be serialized")
return return
} }
if item == nil && w.allowInvalid {
w.WriteBytes([]byte{byte(InvalidT)})
return
}
switch t := item.(type) { switch t := item.(type) {
case *ByteArray: case *ByteArray:
@ -120,6 +119,16 @@ func (w *serContext) serialize(item Item) {
delete(w.seen, item) delete(w.seen, item)
case Null: case Null:
w.WriteB(byte(AnyT)) w.WriteB(byte(AnyT))
case nil:
if w.allowInvalid {
w.WriteBytes([]byte{byte(InvalidT)})
} else {
w.Err = errors.New("invalid stack item")
}
}
if w.Err == nil && w.buf != nil && w.buf.Len() > MaxSize {
w.Err = errors.New("too big item")
} }
} }

View file

@ -0,0 +1,21 @@
package stackitem
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestSerializationMaxErr(t *testing.T) {
base := make([]byte, MaxSize/2+1)
item := Make(base)
arr := []Item{item, item.Dup()}
aitem := Make(arr)
_, err := SerializeItem(item)
require.NoError(t, err)
_, err = SerializeItem(aitem)
require.Error(t, err)
}