No panic handler in Zetaclient may halt cross-chain communication
Description
The code under zetaclient/
implements two separate clients — an EVM client for all EVM-compatible chains and a Bitcoin client for the Bitcoin chain. The clients are intended to relay transactions between chains as well as watch for cross-chain interactions (via emitted events).
Impact
In the event that a panic occurs in the zetaclient
code, the client will simply crash. If a malicious actor is able to find a reliable way to cause panics, they can effectively halt all cross-chain communications by crashing all of the clients for that specific chain.
We discovered a bug in the Bitcoin client that can allow a malicious actor to achieve this; however, there may be numerous other ways to do this. The bug exists in the Bitcoin client's TryProcessOutTx()
function.
func (signer *BTCSigner) TryProcessOutTx(send *types.CrossChainTx, outTxMan *OutTxProcessorManager, outTxID string, chainclient ChainClient, zetaBridge *ZetaCoreBridge) {
// [ ... ]
// FIXME: config chain params
addr, err := btcutil.DecodeAddress(string(toAddr), config.BitconNetParams)
if err != nil {
logger.Error().Err(err).Msgf("cannot decode address %s ", send.GetCurrentOutTxParam().Receiver)
return
}
// [ ... ]
}
Specifically, the call to btcutil.DecodeAddress()
can panic if the toAddr
provided to it is not a valid Bitcoin address. This is easily achieved by passing in an EVM-compatible address instead. The following stack trace is observed when the crash occurs:
zetaclient0 | panic: runtime error: index out of range [65533] with length 256
zetaclient0 |
zetaclient0 | goroutine 12508 [running]:
zetaclient0 | github.com/btcsuite/btcutil/base58.Decode({0xc005e9f968, 0x14})
zetaclient0 | /go/pkg/mod/github.com/btcsuite/btcutil@v1.0.3-0.20201208143702-a53e38424cce/base58/base58.go:58 +0x305
zetaclient0 | github.com/btcsuite/btcutil/base58.CheckDecode({0xc005e9f968?, 0xc001300000?})
zetaclient0 | /go/pkg/mod/github.com/btcsuite/btcutil@v1.0.3-0.20201208143702-a53e38424cce/base58/base58check.go:39 +0x25
zetaclient0 | github.com/btcsuite/btcutil.DecodeAddress({0xc005e9f968?, 0xc0061a6de0?}, 0x458b080)
zetaclient0 | /go/pkg/mod/github.com/btcsuite/btcutil@v1.0.3-0.20201208143702-a53e38424cce/address.go:182 +0x2aa
zetaclient0 | github.com/zeta-chain/zetacore/zetaclient.(*BTCSigner).TryProcessOutTx(0xc004aed680, 0xc006691680, 0xc00053aab0, {0xc00484edc0, 0x4a}, {0x32c9040?, 0xc0050ba200}, 0xc000e9af00)
zetaclient0 | /go/delivery/zeta-node/zetaclient/btc_signer.go:213 +0x893
zetaclient0 | created by github.com/zeta-chain/zetacore/zetaclient.(*CoreObserver).startSendScheduler
zetaclient0 | /go/delivery/zeta-node/zetaclient/zetacore_observer.go:224 +0x1045
Recommendations
The bug demonstrated above is in an external package that is not maintained by the ZetaChain team. Since it is not sustainable to go through and fix any such bugs that arise from the use of external packages, we recommend adding a panic handler to the Zetaclient code so that panics are handled gracefully and preferably logged, so they can be taken care of later.
Remediation
This issue has been acknowledged by ZetaChain, and a fix was implemented in commit f2adb252↗.