Skip to content

Commit

Permalink
smartcontract: restrict maximum NEF file size on deserialisation
Browse files Browse the repository at this point in the history
Port neo-project/neo#2939.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
  • Loading branch information
AnnaShaleva committed Nov 20, 2023
1 parent b220594 commit 14d9881
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 4 deletions.
9 changes: 6 additions & 3 deletions pkg/smartcontract/nef/nef.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"bytes"
"encoding/binary"
"errors"
"fmt"

"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)

// NEO Executable Format 3 (NEF3)
Expand All @@ -31,8 +33,6 @@ import (
const (
// Magic is a magic File header constant.
Magic uint32 = 0x3346454E
// MaxScriptLength is the maximum allowed contract script length.
MaxScriptLength = 512 * 1024
// MaxSourceURLLength is the maximum allowed source URL length.
MaxSourceURLLength = 256
// compilerFieldSize is the length of `Compiler` File header field in bytes.
Expand Down Expand Up @@ -139,7 +139,7 @@ func (n *File) DecodeBinary(r *io.BinReader) {
r.Err = errInvalidReserved
return
}
n.Script = r.ReadVarBytes(MaxScriptLength)
n.Script = r.ReadVarBytes(stackitem.MaxSize)
if r.Err == nil && len(n.Script) == 0 {
r.Err = errors.New("empty script")
return
Expand All @@ -165,6 +165,9 @@ func (n File) Bytes() ([]byte, error) {
// FileFromBytes returns a NEF File deserialized from the given bytes.
func FileFromBytes(source []byte) (File, error) {
result := File{}
if len(source) > stackitem.MaxSize {
return result, fmt.Errorf("invalid NEF file size: expected %d at max, got %d", stackitem.MaxSize, len(source))
}
r := io.NewBinReaderFromBuf(source)
result.DecodeBinary(r)
if r.Err != nil {
Expand Down
27 changes: 26 additions & 1 deletion pkg/smartcontract/nef/nef_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -49,7 +50,7 @@ func TestEncodeDecodeBinary(t *testing.T) {
})

t.Run("invalid script length", func(t *testing.T) {
newScript := make([]byte, MaxScriptLength+1)
newScript := make([]byte, stackitem.MaxSize+1)
expected.Script = newScript
expected.Checksum = expected.CalculateChecksum()
checkDecodeError(t, expected)
Expand Down Expand Up @@ -126,6 +127,30 @@ func TestBytesFromBytes(t *testing.T) {
require.Equal(t, expected, actual)
}

func TestNewFileFromBytesLimits(t *testing.T) {
expected := File{
Header: Header{
Magic: Magic,
Compiler: "best compiler version 1",
},
Tokens: []MethodToken{{
Hash: random.Uint160(),
Method: "someMethod",
ParamCount: 3,
HasReturn: true,
CallFlag: callflag.WriteStates,
}},
Script: make([]byte, stackitem.MaxSize-100),
}
expected.Checksum = expected.CalculateChecksum()

bytes, err := expected.Bytes()
require.NoError(t, err)
_, err = FileFromBytes(bytes)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid NEF file size")
}

func TestMarshalUnmarshalJSON(t *testing.T) {
expected := &File{
Header: Header{
Expand Down

0 comments on commit 14d9881

Please sign in to comment.