Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vm: add two proof verifier to fix the vulnerability in range proof #1121

Merged
merged 14 commits into from
Oct 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## v1.1.16
* [\#1121](https://github.com/bnb-chain/bsc/pull/1121) vm: add two proof verifier to fix the vulnerability in range proof

## v1.1.15
* [\#1109](https://github.com/bnb-chain/bsc/pull/1109) nanofork: block exploitation accounts and suspend cross chain bridge related precompile contracts

Expand Down
6 changes: 6 additions & 0 deletions accounts/abi/bind/bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2023,6 +2023,12 @@ func TestGolangBindings(t *testing.T) {
if out, err := replacer.CombinedOutput(); err != nil {
t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out)
}

replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/tendermint/[email protected]", "-replace", "github.com/tendermint/tendermint=github.com/bnb-chain/[email protected]") // Repo root
replacer.Dir = pkg
if out, err := replacer.CombinedOutput(); err != nil {
t.Fatalf("failed to replace tendermint dependency to bnb-chain source: %v\n%s", err, out)
}
tidier := exec.Command(gocmd, "mod", "tidy")
tidier.Dir = pkg
if out, err := tidier.CombinedOutput(); err != nil {
Expand Down
69 changes: 69 additions & 0 deletions core/systemcontracts/upgrade.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion core/types/blacklist.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package types

import "github.com/ethereum/go-ethereum/common"

// This is introduced because of the Tendermint IAVL Merkel Proof verification exploitation.
// This is introduced because of the Tendermint IAVL Merkle Proof verification exploitation.
var NanoBlackList = []common.Address{
common.HexToAddress("0x489A8756C18C0b8B24EC2a2b9FF3D4d447F79BEc"),
common.HexToAddress("0xFd6042Df3D74ce9959922FeC559d7995F3933c55"),
Expand Down
22 changes: 22 additions & 0 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,21 @@ var PrecompiledContractsIsNano = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{101}): &iavlMerkleProofValidateNano{},
}

var PrecompiledContractsIsMoran = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},

common.BytesToAddress([]byte{100}): &tmHeaderValidate{},
common.BytesToAddress([]byte{101}): &iavlMerkleProofValidateMoran{},
}

// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
// contracts used in the Berlin release.
var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{
Expand Down Expand Up @@ -125,6 +140,7 @@ var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
}

var (
PrecompiledAddressesMoran []common.Address
PrecompiledAddressesNano []common.Address
PrecompiledAddressesBerlin []common.Address
PrecompiledAddressesIstanbul []common.Address
Expand All @@ -148,11 +164,17 @@ func init() {
for k := range PrecompiledContractsIsNano {
PrecompiledAddressesNano = append(PrecompiledAddressesNano, k)
}

for k := range PrecompiledContractsIsMoran {
PrecompiledAddressesMoran = append(PrecompiledAddressesMoran, k)
}
}

// ActivePrecompiles returns the precompiles enabled with the current configuration.
func ActivePrecompiles(rules params.Rules) []common.Address {
switch {
case rules.IsMoran:
return PrecompiledAddressesMoran
case rules.IsNano:
return PrecompiledAddressesNano
case rules.IsBerlin:
Expand Down
124 changes: 103 additions & 21 deletions core/vm/contracts_lightclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import (
"encoding/binary"
"fmt"

"github.com/tendermint/iavl"
"github.com/tendermint/tendermint/crypto/merkle"
cmn "github.com/tendermint/tendermint/libs/common"

"github.com/ethereum/go-ethereum/core/vm/lightclient"
"github.com/ethereum/go-ethereum/params"
)
Expand Down Expand Up @@ -93,8 +97,10 @@ func (c *tmHeaderValidate) Run(input []byte) (result []byte, err error) {

//------------------------------------------------------------------------------------------------------------------------------------------------

// tmHeaderValidate implemented as a native contract.
type iavlMerkleProofValidate struct{}
// iavlMerkleProofValidate implemented as a native contract.
type iavlMerkleProofValidate struct {
basicIavlMerkleProofValidate
}

func (c *iavlMerkleProofValidate) RequiredGas(input []byte) uint64 {
return params.IAVLMerkleProofValidateGas
Expand All @@ -104,7 +110,54 @@ func (c *iavlMerkleProofValidate) RequiredGas(input []byte) uint64 {
// | payload length | payload |
// | 32 bytes | |
func (c *iavlMerkleProofValidate) Run(input []byte) (result []byte, err error) {
//return nil, fmt.Errorf("suspend")
return c.basicIavlMerkleProofValidate.Run(input)
}

// tmHeaderValidate implemented as a native contract.
type tmHeaderValidateNano struct{}

func (c *tmHeaderValidateNano) RequiredGas(input []byte) uint64 {
return params.TendermintHeaderValidateGas
}

func (c *tmHeaderValidateNano) Run(input []byte) (result []byte, err error) {
return nil, fmt.Errorf("suspend")
}

type iavlMerkleProofValidateNano struct{}

func (c *iavlMerkleProofValidateNano) RequiredGas(_ []byte) uint64 {
return params.IAVLMerkleProofValidateGas
}

func (c *iavlMerkleProofValidateNano) Run(_ []byte) (result []byte, err error) {
return nil, fmt.Errorf("suspend")
}

//------------------------------------------------------------------------------------------------------------------------------------------------
type iavlMerkleProofValidateMoran struct {
basicIavlMerkleProofValidate
}

func (c *iavlMerkleProofValidateMoran) RequiredGas(_ []byte) uint64 {
return params.IAVLMerkleProofValidateGas
}

func (c *iavlMerkleProofValidateMoran) Run(input []byte) (result []byte, err error) {
c.basicIavlMerkleProofValidate.verifiers = []merkle.ProofOpVerifier{
forbiddenAbsenceOpVerifier,
singleValueOpVerifier,
multiStoreOpVerifier,
forbiddenSimpleValueOpVerifier,
}
return c.basicIavlMerkleProofValidate.Run(input)
}

type basicIavlMerkleProofValidate struct {
verifiers []merkle.ProofOpVerifier
}

func (c *basicIavlMerkleProofValidate) Run(input []byte) (result []byte, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("internal error: %v\n", r)
Expand All @@ -124,7 +177,7 @@ func (c *iavlMerkleProofValidate) Run(input []byte) (result []byte, err error) {
if err != nil {
return nil, err
}

kvmp.SetVerifiers(c.verifiers)
valid := kvmp.Validate()
if !valid {
return nil, fmt.Errorf("invalid merkle proof")
Expand All @@ -135,27 +188,56 @@ func (c *iavlMerkleProofValidate) Run(input []byte) (result []byte, err error) {
return result, nil
}

// tmHeaderValidate implemented as a native contract.
type tmHeaderValidateNano struct{}

func (c *tmHeaderValidateNano) RequiredGas(input []byte) uint64 {
return params.TendermintHeaderValidateGas
func forbiddenAbsenceOpVerifier(op merkle.ProofOperator) error {
owen-reorg marked this conversation as resolved.
Show resolved Hide resolved
if op == nil {
return nil
}
if _, ok := op.(iavl.IAVLAbsenceOp); ok {
return cmn.NewError("absence proof suspend")
}
return nil
}

func (c *tmHeaderValidateNano) Run(input []byte) (result []byte, err error) {
return nil, fmt.Errorf("suspend")
func forbiddenSimpleValueOpVerifier(op merkle.ProofOperator) error {
if op == nil {
return nil
}
if _, ok := op.(merkle.SimpleValueOp); ok {
return cmn.NewError("simple value proof suspend")
}
return nil
}

//------------------------------------------------------------------------------------------------------------------------------------------------
type iavlMerkleProofValidateNano struct{}

func (c *iavlMerkleProofValidateNano) RequiredGas(input []byte) uint64 {
return params.IAVLMerkleProofValidateGas
func multiStoreOpVerifier(op merkle.ProofOperator) error {
if op == nil {
return nil
}
if mop, ok := op.(lightclient.MultiStoreProofOp); ok {
storeNames := make(map[string]bool, len(mop.Proof.StoreInfos))
for _, store := range mop.Proof.StoreInfos {
if exist := storeNames[store.Name]; exist {
return cmn.NewError("duplicated store")
} else {
storeNames[store.Name] = true
}
}
}
return nil
}

// input:
// | payload length | payload |
// | 32 bytes | |
func (c *iavlMerkleProofValidateNano) Run(input []byte) (result []byte, err error) {
return nil, fmt.Errorf("suspend")
func singleValueOpVerifier(op merkle.ProofOperator) error {
if op == nil {
return nil
}
if valueOp, ok := op.(iavl.IAVLValueOp); ok {
if len(valueOp.Proof.Leaves) != 1 {
brilliant-lx marked this conversation as resolved.
Show resolved Hide resolved
return cmn.NewError("range proof suspended")
}
for _, innerNode := range valueOp.Proof.LeftPath {
if len(innerNode.Right) > 0 && len(innerNode.Left) > 0 {
return cmn.NewError("both right and left hash exit!")
}
}
}
return nil
}
Loading