[#822] event/notaryPreparator: Do not pass PACK opcode

Do not pass high level `PACK` opcode to
notary parsers. Add opcode amount check.
Delete `PACK` cases in notary parsers.

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
Pavel Karpy 2021-09-10 20:29:15 +03:00 committed by Alex Vanin
parent 4f3de1a9af
commit 3b9ef4f63c
4 changed files with 70 additions and 21 deletions

View file

@ -57,8 +57,6 @@ func ParseDeleteNotary(ne event.NotaryEvent) (event.Event, error) {
deleteFieldSetters[fieldNum](&ev, op.Param()) deleteFieldSetters[fieldNum](&ev, op.Param())
fieldNum++ fieldNum++
case opcode.PUSH0 <= currentOp && currentOp <= opcode.PUSH16 || currentOp == opcode.PACK:
// array packing opcodes. do nothing with it
default: default:
return nil, event.UnexpectedOpcode(DeleteNotaryEvent, op.Code()) return nil, event.UnexpectedOpcode(DeleteNotaryEvent, op.Code())
} }

View file

@ -64,8 +64,6 @@ func ParseSetEACLNotary(ne event.NotaryEvent) (event.Event, error) {
setEACLFieldSetters[fieldNum](&ev, op.Param()) setEACLFieldSetters[fieldNum](&ev, op.Param())
fieldNum++ fieldNum++
case opcode.PUSH0 <= currentOp && currentOp <= opcode.PUSH16 || currentOp == opcode.PACK:
// array packing opcodes. do nothing with it
default: default:
return nil, event.UnexpectedOpcode(SetEACLNotaryEvent, op.Code()) return nil, event.UnexpectedOpcode(SetEACLNotaryEvent, op.Code())
} }

View file

@ -64,8 +64,6 @@ func ParsePutNotary(ne event.NotaryEvent) (event.Event, error) {
putFieldSetters[fieldNum](&ev, op.Param()) putFieldSetters[fieldNum](&ev, op.Param())
fieldNum++ fieldNum++
case opcode.PUSH0 <= currentOp && currentOp <= opcode.PUSH16 || currentOp == opcode.PACK:
// array packing opcodes. do nothing with it
default: default:
return nil, event.UnexpectedOpcode(PutNotaryEvent, op.Code()) return nil, event.UnexpectedOpcode(PutNotaryEvent, op.Code())
} }

View file

@ -29,8 +29,9 @@ var (
errIncorrectNotaryPlaceholder = errors.New("received main tx has incorrect Notary contract placeholder") errIncorrectNotaryPlaceholder = errors.New("received main tx has incorrect Notary contract placeholder")
errIncorrectAttributesAmount = errors.New("received main tx has incorrect attributes amount") errIncorrectAttributesAmount = errors.New("received main tx has incorrect attributes amount")
errIncorrectAttribute = errors.New("received main tx has incorrect attribute") errIncorrectAttribute = errors.New("received main tx has incorrect attribute")
errUnexpectedOpcode = errors.New("received main tx has unexpected(not PUSH) NeoVM opcodes")
errIncorrectCallFlag = errors.New("received main tx has unexpected call flag") errIncorrectCallFlag = errors.New("received main tx has unexpected call flag")
errIncorrectArgPacking = errors.New("received main tx has incorrect argument packing")
errUnexpectedCONVERT = errors.New("received main tx has unexpected CONVERT opcode")
errIncorrectFBAttributesAmount = errors.New("received fallback tx has incorrect attributes amount") errIncorrectFBAttributesAmount = errors.New("received fallback tx has incorrect attributes amount")
errIncorrectFBAttributes = errors.New("received fallback tx has incorrect attributes") errIncorrectFBAttributes = errors.New("received fallback tx has incorrect attributes")
@ -154,7 +155,7 @@ func (p Preparator) Prepare(nr *payload.P2PNotaryRequest) (NotaryEvent, error) {
) )
ctx := vm.NewContext(nr.MainTransaction.Script) ctx := vm.NewContext(nr.MainTransaction.Script)
ops := make([]Op, 0, 16) // 16 is maximum num of opcodes for calling contracts with 4 args(no arrays of arrays) ops := make([]Op, 0, 10) // 10 is maximum num of opcodes for calling contracts with 4 args(no arrays of arrays)
for { for {
opCode, param, err = ctx.Next() opCode, param, err = ctx.Next()
@ -191,31 +192,85 @@ func (p Preparator) Prepare(nr *payload.P2PNotaryRequest) (NotaryEvent, error) {
return nil, errIncorrectCallFlag return nil, errIncorrectCallFlag
} }
err = p.validateParameterOpcodes(ops[:opsLen-4]) args := ops[:opsLen-4]
if len(args) != 0 {
err = p.validateParameterOpcodes(args)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("could not validate arguments: %w", err)
}
// without args packing opcodes
args = args[:len(args)-2]
} }
return parsedNotaryEvent{ return parsedNotaryEvent{
hash: contractHash, hash: contractHash,
notaryType: NotaryTypeFromString(contractMethod), notaryType: NotaryTypeFromString(contractMethod),
params: ops[:opsLen-4], params: args,
raw: nr, raw: nr,
}, nil }, nil
} }
func (p Preparator) validateParameterOpcodes(oo []Op) error { func (p Preparator) validateParameterOpcodes(ops []Op) error {
// check for unexpected NeoVM opcodes l := len(ops)
for _, o := range oo {
switch { if ops[l-1].code != opcode.PACK {
// only PUSH(and PACK for arrays) codes are allowed; return fmt.Errorf("unexpected packing opcode: %s", ops[l-1].code)
// number of params and their content must be checked
// in a notary parser and a notary handler of a
// particular contract
case o.code <= opcode.PUSH16 || o.code == opcode.PACK:
default:
return errUnexpectedOpcode
} }
argsLen, err := IntFromOpcode(ops[l-2])
if err != nil {
return fmt.Errorf("could not parse argument len: %w", err)
}
err = validateNestedArgs(argsLen, ops[:l-2])
if err != nil {
return err
}
return nil
}
func validateNestedArgs(expArgLen int64, ops []Op) error {
var (
currentCode opcode.Opcode
opsLenGot = len(ops)
)
for i := opsLenGot - 1; i >= 0; i-- {
// only PUSH(also, PACK for arrays and CONVERT for booleans)
// codes are allowed; number of params and their content must
// be checked in a notary parser and a notary handler of a
// particular contract
switch currentCode = ops[i].code; {
case currentCode <= opcode.PUSH16:
case currentCode == opcode.CONVERT:
if i == 0 || ops[i-1].code != opcode.PUSHT && ops[i-1].code != opcode.PUSHF {
return errUnexpectedCONVERT
}
expArgLen++
case currentCode == opcode.PACK:
if i == 0 {
return errIncorrectArgPacking
}
argsLen, err := IntFromOpcode(ops[i-1])
if err != nil {
return fmt.Errorf("could not parse argument len: %w", err)
}
expArgLen += argsLen + 1
i--
default:
return fmt.Errorf("received main tx has unexpected(not PUSH) NeoVM opcode: %s", currentCode)
}
}
if int64(opsLenGot) != expArgLen {
return errIncorrectArgPacking
} }
return nil return nil