From 23c6fcdbe834b70ff25473e6ff03da94814609c1 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Mon, 17 Jul 2017 14:25:46 +0200 Subject: [PATCH] mobile: don't retain transient []byte in CallMsg.SetData (#14804) * mobile: don't retain transient []byte in CallMsg.SetData Go mobile doesn't copy []byte parameters, for performance and to allow writes to the byte array be reflected in the native byte array. Unfortunately, that means []byte arguments are only valid during the call it is being passed into. CallMsg.SetData retains such a byte array. Copy it instead Fixes #14675 * mobile: copy all []byte arguments from gomobile To avoid subtle errors when accidentially retaining an otherwise transient byte slice coming from gomobile, copy all byte slices before use. * mobile: replace copySlice with common.CopyBytes --- mobile/accounts.go | 11 ++++++----- mobile/big.go | 4 +++- mobile/bind.go | 2 +- mobile/common.go | 4 ++-- mobile/ethereum.go | 2 +- mobile/interface.go | 2 +- mobile/types.go | 13 +++++++------ 7 files changed, 21 insertions(+), 17 deletions(-) diff --git a/mobile/accounts.go b/mobile/accounts.go index 977999c3a..4d979bfff 100644 --- a/mobile/accounts.go +++ b/mobile/accounts.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) @@ -111,7 +112,7 @@ func (ks *KeyStore) DeleteAccount(account *Account, passphrase string) error { // SignHash calculates a ECDSA signature for the given hash. The produced signature // is in the [R || S || V] format where V is 0 or 1. func (ks *KeyStore) SignHash(address *Address, hash []byte) (signature []byte, _ error) { - return ks.keystore.SignHash(accounts.Account{Address: address.address}, hash) + return ks.keystore.SignHash(accounts.Account{Address: address.address}, common.CopyBytes(hash)) } // SignTx signs the given transaction with the requested account. @@ -130,7 +131,7 @@ func (ks *KeyStore) SignTx(account *Account, tx *Transaction, chainID *BigInt) ( // be decrypted with the given passphrase. The produced signature is in the // [R || S || V] format where V is 0 or 1. func (ks *KeyStore) SignHashPassphrase(account *Account, passphrase string, hash []byte) (signature []byte, _ error) { - return ks.keystore.SignHashWithPassphrase(account.account, passphrase, hash) + return ks.keystore.SignHashWithPassphrase(account.account, passphrase, common.CopyBytes(hash)) } // SignTxPassphrase signs the transaction if the private key matching the @@ -189,7 +190,7 @@ func (ks *KeyStore) ExportKey(account *Account, passphrase, newPassphrase string // ImportKey stores the given encrypted JSON key into the key directory. func (ks *KeyStore) ImportKey(keyJSON []byte, passphrase, newPassphrase string) (account *Account, _ error) { - acc, err := ks.keystore.Import(keyJSON, passphrase, newPassphrase) + acc, err := ks.keystore.Import(common.CopyBytes(keyJSON), passphrase, newPassphrase) if err != nil { return nil, err } @@ -198,7 +199,7 @@ func (ks *KeyStore) ImportKey(keyJSON []byte, passphrase, newPassphrase string) // ImportECDSAKey stores the given encrypted JSON key into the key directory. func (ks *KeyStore) ImportECDSAKey(key []byte, passphrase string) (account *Account, _ error) { - privkey, err := crypto.ToECDSA(key) + privkey, err := crypto.ToECDSA(common.CopyBytes(key)) if err != nil { return nil, err } @@ -212,7 +213,7 @@ func (ks *KeyStore) ImportECDSAKey(key []byte, passphrase string) (account *Acco // ImportPreSaleKey decrypts the given Ethereum presale wallet and stores // a key file in the key directory. The key file is encrypted with the same passphrase. func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (ccount *Account, _ error) { - account, err := ks.keystore.ImportPreSaleKey(keyJSON, passphrase) + account, err := ks.keystore.ImportPreSaleKey(common.CopyBytes(keyJSON), passphrase) if err != nil { return nil, err } diff --git a/mobile/big.go b/mobile/big.go index 525717caa..564fbad47 100644 --- a/mobile/big.go +++ b/mobile/big.go @@ -21,6 +21,8 @@ package geth import ( "errors" "math/big" + + "github.com/ethereum/go-ethereum/common" ) // A BigInt represents a signed multi-precision integer. @@ -52,7 +54,7 @@ func (bi *BigInt) GetInt64() int64 { // SetBytes interprets buf as the bytes of a big-endian unsigned integer and sets // the big int to that value. func (bi *BigInt) SetBytes(buf []byte) { - bi.bigint.SetBytes(buf) + bi.bigint.SetBytes(common.CopyBytes(buf)) } // SetInt64 sets the big int to x. diff --git a/mobile/bind.go b/mobile/bind.go index bc4eb25ba..084d6ef4c 100644 --- a/mobile/bind.go +++ b/mobile/bind.go @@ -119,7 +119,7 @@ func DeployContract(opts *TransactOpts, abiJSON string, bytecode []byte, client if err != nil { return nil, err } - addr, tx, bound, err := bind.DeployContract(&opts.opts, parsed, bytecode, client.client, args.objects...) + addr, tx, bound, err := bind.DeployContract(&opts.opts, parsed, common.CopyBytes(bytecode), client.client, args.objects...) if err != nil { return nil, err } diff --git a/mobile/common.go b/mobile/common.go index 3090014c5..047d8e1f6 100644 --- a/mobile/common.go +++ b/mobile/common.go @@ -35,7 +35,7 @@ type Hash struct { // NewHashFromBytes converts a slice of bytes to a hash value. func NewHashFromBytes(binary []byte) (hash *Hash, _ error) { h := new(Hash) - if err := h.SetBytes(binary); err != nil { + if err := h.SetBytes(common.CopyBytes(binary)); err != nil { return nil, err } return h, nil @@ -136,7 +136,7 @@ type Address struct { // NewAddressFromBytes converts a slice of bytes to a hash value. func NewAddressFromBytes(binary []byte) (address *Address, _ error) { a := new(Address) - if err := a.SetBytes(binary); err != nil { + if err := a.SetBytes(common.CopyBytes(binary)); err != nil { return nil, err } return a, nil diff --git a/mobile/ethereum.go b/mobile/ethereum.go index 30a94dc89..c9bb3013c 100644 --- a/mobile/ethereum.go +++ b/mobile/ethereum.go @@ -64,7 +64,7 @@ func (msg *CallMsg) SetFrom(address *Address) { msg.msg.From = address.address func (msg *CallMsg) SetGas(gas int64) { msg.msg.Gas = big.NewInt(gas) } func (msg *CallMsg) SetGasPrice(price *BigInt) { msg.msg.GasPrice = price.bigint } func (msg *CallMsg) SetValue(value *BigInt) { msg.msg.Value = value.bigint } -func (msg *CallMsg) SetData(data []byte) { msg.msg.Data = data } +func (msg *CallMsg) SetData(data []byte) { msg.msg.Data = common.CopyBytes(data) } func (msg *CallMsg) SetTo(address *Address) { if address == nil { msg.msg.To = nil diff --git a/mobile/interface.go b/mobile/interface.go index 10eac5f72..72958e66a 100644 --- a/mobile/interface.go +++ b/mobile/interface.go @@ -46,7 +46,7 @@ func (i *Interface) SetBool(b bool) { i.object = &b } func (i *Interface) SetBools(bs []bool) { i.object = &bs } func (i *Interface) SetString(str string) { i.object = &str } func (i *Interface) SetStrings(strs *Strings) { i.object = &strs.strs } -func (i *Interface) SetBinary(binary []byte) { i.object = &binary } +func (i *Interface) SetBinary(binary []byte) { b := common.CopyBytes(binary); i.object = &b } func (i *Interface) SetBinaries(binaries [][]byte) { i.object = &binaries } func (i *Interface) SetAddress(address *Address) { i.object = &address.address } func (i *Interface) SetAddresses(addrs *Addresses) { i.object = &addrs.addresses } diff --git a/mobile/types.go b/mobile/types.go index 4c4cd8822..088c7c6b3 100644 --- a/mobile/types.go +++ b/mobile/types.go @@ -23,6 +23,7 @@ import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" ) @@ -68,7 +69,7 @@ func NewHeaderFromRLP(data []byte) (*Header, error) { h := &Header{ header: new(types.Header), } - if err := rlp.DecodeBytes(data, h.header); err != nil { + if err := rlp.DecodeBytes(common.CopyBytes(data), h.header); err != nil { return nil, err } return h, nil @@ -145,7 +146,7 @@ func NewBlockFromRLP(data []byte) (*Block, error) { b := &Block{ block: new(types.Block), } - if err := rlp.DecodeBytes(data, b.block); err != nil { + if err := rlp.DecodeBytes(common.CopyBytes(data), b.block); err != nil { return nil, err } return b, nil @@ -212,7 +213,7 @@ type Transaction struct { // NewTransaction creates a new transaction with the given properties. func NewTransaction(nonce int64, to *Address, amount, gasLimit, gasPrice *BigInt, data []byte) *Transaction { - return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, gasLimit.bigint, gasPrice.bigint, data)} + return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, gasLimit.bigint, gasPrice.bigint, common.CopyBytes(data))} } // NewTransactionFromRLP parses a transaction from an RLP data dump. @@ -220,7 +221,7 @@ func NewTransactionFromRLP(data []byte) (*Transaction, error) { tx := &Transaction{ tx: new(types.Transaction), } - if err := rlp.DecodeBytes(data, tx.tx); err != nil { + if err := rlp.DecodeBytes(common.CopyBytes(data), tx.tx); err != nil { return nil, err } return tx, nil @@ -285,7 +286,7 @@ func (tx *Transaction) WithSignature(sig []byte, chainID *BigInt) (signedTx *Tra if chainID != nil { signer = types.NewEIP155Signer(chainID.bigint) } - rawTx, err := tx.tx.WithSignature(signer, sig) + rawTx, err := tx.tx.WithSignature(signer, common.CopyBytes(sig)) return &Transaction{rawTx}, err } @@ -315,7 +316,7 @@ func NewReceiptFromRLP(data []byte) (*Receipt, error) { r := &Receipt{ receipt: new(types.Receipt), } - if err := rlp.DecodeBytes(data, r.receipt); err != nil { + if err := rlp.DecodeBytes(common.CopyBytes(data), r.receipt); err != nil { return nil, err } return r, nil