vm: restrict map key size

This commit is contained in:
Anna Shaleva 2020-09-29 10:56:57 +03:00
parent 1f9b92c295
commit 543fd58e93
5 changed files with 20 additions and 11 deletions

View file

@ -24,6 +24,7 @@ a dialect of Go rather than a complete port of the language:
overhead for all contracts. This can easily be mitigated by first storing values
in variables and returning the result.
* lambdas are supported, but closures are not.
* maps are supported, but valid map keys are booleans, integers and strings with length <= 64
## VM API (interop layer)
Compiler translates interop function calls into NEO VM syscalls or (for custom

View file

@ -27,6 +27,8 @@ const (
// MaxByteArrayComparableSize is the maximum allowed length of ByteArray for Equals method.
// It is set to be the maximum uint16 value.
MaxByteArrayComparableSize = math.MaxUint16
// MaxKeySize is the maximum size of map key.
MaxKeySize = 64
)
// Item represents the "real" value that is pushed on the stack.
@ -773,8 +775,8 @@ func (i *Map) Convert(typ Type) (Item, error) {
// Add adds key-value pair to the map.
func (i *Map) Add(key, value Item) {
if !IsValidMapKey(key) {
panic("wrong key type")
if err := IsValidMapKey(key); err != nil {
panic(err)
}
index := i.Index(key)
if index >= 0 {
@ -792,12 +794,18 @@ func (i *Map) Drop(index int) {
// IsValidMapKey checks whether it's possible to use given Item as a Map
// key.
func IsValidMapKey(key Item) bool {
func IsValidMapKey(key Item) error {
switch key.(type) {
case *Bool, *BigInteger, *ByteArray:
return true
case *Bool, *BigInteger:
return nil
case *ByteArray:
size := len(key.Value().([]byte))
if size > MaxKeySize {
return fmt.Errorf("invalid map key size: %d", size)
}
return nil
default:
return false
return fmt.Errorf("invalid map key of type %s", key.Type())
}
}

View file

@ -360,8 +360,8 @@ func FromJSONWithTypes(data []byte) (Item, error) {
key, err := FromJSONWithTypes(arr[i].Key)
if err != nil {
return nil, err
} else if !IsValidMapKey(key) {
return nil, fmt.Errorf("invalid map key of type %s", key.Type())
} else if err = IsValidMapKey(key); err != nil {
return nil, err
}
value, err := FromJSONWithTypes(arr[i].Value)
if err != nil {

View file

@ -88,7 +88,7 @@ func TestFromToJSON(t *testing.T) {
t.Run("BigNestedArray", getTestDecodeFunc(`[[[[[[[[[[[]]]]]]]]]]]`, nil))
t.Run("EncodeRecursive", func(t *testing.T) {
// add this item to speed up test a bit
item := NewByteArray(make([]byte, MaxSize/100))
item := NewByteArray(make([]byte, MaxKeySize))
t.Run("Array", func(t *testing.T) {
arr := NewArray([]Item{item})
arr.Append(arr)

View file

@ -1668,8 +1668,8 @@ func validateMapKey(key *Element) {
if key == nil {
panic("no key found")
}
if !stackitem.IsValidMapKey(key.Item()) {
panic("key can't be a collection")
if err := stackitem.IsValidMapKey(key.Item()); err != nil {
panic(err)
}
}