Skip to content

Contract with out-of-script-bounds method offset is allowed to be deployed #2767

@AnnaShaleva

Description

@AnnaShaleva

Describe the bug
It is allowed to deploy contract with method offset that is out of the contract script bounds. Here's the Management's check:

Helper.Check(nef.Script, parsedManifest.Abi);
Where Helper tries to retrieve instruction by the specified offset for each method:
script.GetInstruction(method.Offset);
However, if the instruction is out of script bounds, then RET is returned and no exception occurs: https://github.com/neo-project/neo-vm/blob/a65487fa56be3eccb2c1dbfec5dcdd71b8a05fde/src/Neo.VM/Script.cs#L146. Thus, the contract script check is passed.

To Reproduce
Block 125000 of current T5 contains the following deploying transaction:

         {
            "version" : 0,
            "sysfee" : "1000106065",
            "validuntilblock" : 130758,
            "script" : "DdMDeyJuYW1lIjoiTmVwMTdUb2tlbiIsImdyb3VwcyI6W10sImZlYXR1cmVzIjp7fSwic3VwcG9ydGVkc3RhbmRhcmRzIjpbIk5FUC0xNyJdLCJhYmkiOnsibWV0aG9kcyI6W3sibmFtZSI6InN5bWJvbCIsInBhcmFtZXRlcnMiOltdLCJyZXR1cm50eXBlIjoiU3RyaW5nIiwib2Zmc2V0IjoyMiwic2FmZSI6dHJ1ZX0seyJuYW1lIjoiZGVjaW1hbHMiLCJwYXJhbWV0ZXJzIjpbXSwicmV0dXJudHlwZSI6IkludGVnZXIiLCJvZmZzZXQiOjIyLCJzYWZlIjp0cnVlfSx7Im5hbWUiOiJ0b3RhbFN1cHBseSIsInBhcmFtZXRlcnMiOltdLCJyZXR1cm50eXBlIjoiSW50ZWdlciIsIm9mZnNldCI6MjIsInNhZmUiOnRydWV9LHsibmFtZSI6ImJhbGFuY2VPZiIsInBhcmFtZXRlcnMiOlt7Im5hbWUiOiJvd25lciIsInR5cGUiOiJIYXNoMTYwIn1dLCJyZXR1cm50eXBlIjoiSW50ZWdlciIsIm9mZnNldCI6MjIsInNhZmUiOnRydWV9LHsibmFtZSI6InRyYW5zZmVyIiwicGFyYW1ldGVycyI6W3sibmFtZSI6ImZyb20iLCJ0eXBlIjoiSGFzaDE2MCJ9LHsibmFtZSI6InRvIiwidHlwZSI6Ikhhc2gxNjAifSx7Im5hbWUiOiJhbW91bnQiLCJ0eXBlIjoiSW50ZWdlciJ9LHsibmFtZSI6ImRhdGEiLCJ0eXBlIjoiQW55In1dLCJyZXR1cm50eXBlIjoiQm9vbGVhbiIsIm9mZnNldCI6MjIsInNhZmUiOmZhbHNlfV0sImV2ZW50cyI6W3sibmFtZSI6IlRyYW5zZmVyIiwicGFyYW1ldGVycyI6W3sibmFtZSI6ImZyb20iLCJ0eXBlIjoiSGFzaDE2MCJ9LHsibmFtZSI6InRvIiwidHlwZSI6Ikhhc2gxNjAifSx7Im5hbWUiOiJhbW91bnQiLCJ0eXBlIjoiSW50ZWdlciJ9XX1dfSwicGVybWlzc2lvbnMiOlt7ImNvbnRyYWN0IjoiKiIsIm1ldGhvZHMiOiIqIn1dLCJ0cnVzdHMiOltdLCJleHRyYSI6eyJlbWFpbCI6ImRldmVsb3BlckBuZW8ub3JnIiwiYXV0aG9yIjoibGF6eW5vZGUiLCJkZXNjcmlwdGlvbiI6IkEgU2ltcGxlIE5lcC0xNyBDb250cmFjdCJ9fQyyTkVGM25lb21sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOaHR0cHM6Ly9naXRodWIuY29tL2xhenlub2RlL25lb21sL2Jsb2IvZGV2L2V4YW1wbGVzL2EuZnVuY3Rpb24uc2ltcGxlbmVwMTcueG1sAAAAABYMBU5lb01MQBhAAgDh9QVAATkFQBFAkA456BLAHwwGZGVwbG95DBT9o/pDRupTKiWPxJfdrdtkN8n9/0FifVtS",
            "hash" : "0x40302bcf2021f63a1c24f6009e154c3200f73ad2fe1462d7d599145823dbfa7e",
            "witnesses" : [
               {
                  "verification" : "DCECExn08eznGBdguHbcwI+R2//EtVdDx4qf6CeizHqOJgBBVuezJw==",
                  "invocation" : "DEBtoq+T9NrammQjuYnifco7KHCTk2v+woEJqJCUMr9IscS7PaZaN3FNzSt11yUglIi3T0CJ17KwArBOBvJ8kwq2"
               }
            ],
            "attributes" : [],
            "signers" : [
               {
                  "scopes" : "None",
                  "account" : "0x13a192c56738900f9918d7f1ec07d9d8c278b804"
               }
            ],
            "size" : 1360,
            "nonce" : 1829882407,
            "sender" : "NLLvsqs7AyBNmQT6NThUxYWDFwV5b1evaK",
            "netfee" : "234352"
         }

Transaction script contains malformed contract manifest (all methods offsets are set to be 22, while the contract script lenght is 22). Here's the contract manifest:

{
   "name" : "Nep17Token",
   "groups" : [],
   "extra" : {
      "description" : "A Simple Nep-17 Contract",
      "email" : "[email protected]",
      "author" : "lazynode"
   },
   "permissions" : [
      {
         "contract" : "*",
         "methods" : "*"
      }
   ],
   "features" : {},
   "supportedstandards" : [
      "NEP-17"
   ],
   "abi" : {
      "events" : [
         {
            "parameters" : [
               {
                  "name" : "from",
                  "type" : "Hash160"
               },
               {
                  "type" : "Hash160",
                  "name" : "to"
               },
               {
                  "name" : "amount",
                  "type" : "Integer"
               }
            ],
            "name" : "Transfer"
         }
      ],
      "methods" : [
         {
            "safe" : true,
            "offset" : 22,
            "name" : "symbol",
            "returntype" : "String",
            "parameters" : []
         },
         {
            "returntype" : "Integer",
            "parameters" : [],
            "safe" : true,
            "offset" : 22,
            "name" : "decimals"
         },
         {
            "parameters" : [],
            "returntype" : "Integer",
            "name" : "totalSupply",
            "safe" : true,
            "offset" : 22
         },
         {
            "parameters" : [
               {
                  "name" : "owner",
                  "type" : "Hash160"
               }
            ],
            "returntype" : "Integer",
            "name" : "balanceOf",
            "offset" : 22,
            "safe" : true
         },
         {
            "name" : "transfer",
            "offset" : 22,
            "safe" : false,
            "parameters" : [
               {
                  "type" : "Hash160",
                  "name" : "from"
               },
               {
                  "name" : "to",
                  "type" : "Hash160"
               },
               {
                  "name" : "amount",
                  "type" : "Integer"
               },
               {
                  "name" : "data",
                  "type" : "Any"
               }
            ],
            "returntype" : "Boolean"
         }
      ]
   },
   "trusts" : []
}

And here's the contract script itself:

anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ ./bin/neo-go vm

    _   ____________        __________      _    ____  ___
   / | / / ____/ __ \      / ____/ __ \    | |  / /  |/  /
  /  |/ / __/ / / / /_____/ / __/ / / /____| | / / /|_/ / 
 / /|  / /___/ /_/ /_____/ /_/ / /_/ /_____/ |/ / /  / /  
/_/ |_/_____/\____/      \____/\____/      |___/_/  /_/   



NEO-GO-VM > loadhex 0c054e656f4d4c4018400200e1f50540013905401140
READY: loaded 22 instructions
NEO-GO-VM 0 > ops
INDEX    OPCODE       PARAMETER
0        PUSHDATA1    4e656f4d4c ("NeoML")    <<
7        RET          
8        PUSH8        
9        RET          
10       PUSHINT32    100000000 (00e1f505)
15       RET          
16       PUSHINT16    1337 (3905)
19       RET          
20       PUSH1        
21       RET          

Expected behavior
Although VM is able to properly handle the out-of-bounds method offset, it would be better not to allow deploying of such corrupted contracts.

Platform:

  • Version: neo v3.3.0

(Optional) Additional context
The issue was discovered due to T5 statediff, neo-go node didn't allow to deploy such corrupted contract, see the nspcc-dev/neo-go@d1899a4.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions