aboutsummaryrefslogtreecommitdiffstats
path: root/eth
diff options
context:
space:
mode:
authorzelig <viktor.tron@gmail.com>2015-03-28 08:48:37 +0800
committerzelig <viktor.tron@gmail.com>2015-04-01 19:32:42 +0800
commite1be34bce1ddf662bca58a37a6f38fea63a2a70f (patch)
tree5751601efa7f3f88ffd5f9903aa0fecb38667bd4 /eth
parent936ddf2ad1b7306dfe7f5ae9ca122a4968dd98e8 (diff)
downloadgo-tangerine-e1be34bce1ddf662bca58a37a6f38fea63a2a70f.tar.gz
go-tangerine-e1be34bce1ddf662bca58a37a6f38fea63a2a70f.tar.zst
go-tangerine-e1be34bce1ddf662bca58a37a6f38fea63a2a70f.zip
eth: SEC-29 eth wire protocol decoding invalid message data crashes client
- add validate method to types.Block - validate after Decode -> error - add tests for NewBlockMsg
Diffstat (limited to 'eth')
-rw-r--r--eth/protocol.go9
-rw-r--r--eth/protocol_test.go117
2 files changed, 104 insertions, 22 deletions
diff --git a/eth/protocol.go b/eth/protocol.go
index e32ea233b..0a3f67b62 100644
--- a/eth/protocol.go
+++ b/eth/protocol.go
@@ -105,7 +105,7 @@ type getBlockHashesMsgData struct {
type statusMsgData struct {
ProtocolVersion uint32
NetworkId uint32
- TD *big.Int
+ TD big.Int
CurrentBlock common.Hash
GenesisBlock common.Hash
}
@@ -276,6 +276,9 @@ func (self *ethProtocol) handle() error {
if err := msg.Decode(&request); err != nil {
return self.protoError(ErrDecode, "%v: %v", msg, err)
}
+ if err := request.Block.Validate(); err != nil {
+ return self.protoError(ErrDecode, "block validation %v: %v", msg, err)
+ }
hash := request.Block.Hash()
_, chainHead, _ := self.chainManager.Status()
@@ -335,7 +338,7 @@ func (self *ethProtocol) handleStatus() error {
return self.protoError(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, self.protocolVersion)
}
- _, suspended := self.blockPool.AddPeer(status.TD, status.CurrentBlock, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect)
+ _, suspended := self.blockPool.AddPeer(&status.TD, status.CurrentBlock, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect)
if suspended {
return self.protoError(ErrSuspendedPeer, "")
}
@@ -366,7 +369,7 @@ func (self *ethProtocol) sendStatus() error {
return p2p.Send(self.rw, StatusMsg, &statusMsgData{
ProtocolVersion: uint32(self.protocolVersion),
NetworkId: uint32(self.networkId),
- TD: td,
+ TD: *td,
CurrentBlock: currentBlock,
GenesisBlock: genesisBlock,
})
diff --git a/eth/protocol_test.go b/eth/protocol_test.go
index 8ca6d1be6..7831e9bc6 100644
--- a/eth/protocol_test.go
+++ b/eth/protocol_test.go
@@ -1,6 +1,7 @@
package eth
import (
+ "fmt"
"log"
"math/big"
"os"
@@ -63,6 +64,10 @@ func (self *testChainManager) GetBlockHashesFromHash(hash common.Hash, amount ui
func (self *testChainManager) Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) {
if self.status != nil {
td, currentBlock, genesisBlock = self.status()
+ } else {
+ td = common.Big1
+ currentBlock = common.Hash{1}
+ genesisBlock = common.Hash{2}
}
return
}
@@ -163,14 +168,29 @@ func (self *ethProtocolTester) run() {
self.quit <- err
}
+func (self *ethProtocolTester) handshake(t *testing.T, mock bool) {
+ td, currentBlock, genesis := self.chainManager.Status()
+ // first outgoing msg should be StatusMsg.
+ err := p2p.ExpectMsg(self, StatusMsg, &statusMsgData{
+ ProtocolVersion: ProtocolVersion,
+ NetworkId: NetworkId,
+ TD: *td,
+ CurrentBlock: currentBlock,
+ GenesisBlock: genesis,
+ })
+ if err != nil {
+ t.Fatalf("incorrect outgoing status: %v", err)
+ }
+ if mock {
+ go p2p.Send(self, StatusMsg, &statusMsgData{ProtocolVersion, NetworkId, *td, currentBlock, genesis})
+ }
+}
+
func TestStatusMsgErrors(t *testing.T) {
logInit()
eth := newEth(t)
- td := common.Big1
- currentBlock := common.Hash{1}
- genesis := common.Hash{2}
- eth.chainManager.status = func() (*big.Int, common.Hash, common.Hash) { return td, currentBlock, genesis }
go eth.run()
+ td, currentBlock, genesis := eth.chainManager.Status()
tests := []struct {
code uint64
@@ -182,31 +202,20 @@ func TestStatusMsgErrors(t *testing.T) {
wantErrorCode: ErrNoStatusMsg,
},
{
- code: StatusMsg, data: statusMsgData{10, NetworkId, td, currentBlock, genesis},
+ code: StatusMsg, data: statusMsgData{10, NetworkId, *td, currentBlock, genesis},
wantErrorCode: ErrProtocolVersionMismatch,
},
{
- code: StatusMsg, data: statusMsgData{ProtocolVersion, 999, td, currentBlock, genesis},
+ code: StatusMsg, data: statusMsgData{ProtocolVersion, 999, *td, currentBlock, genesis},
wantErrorCode: ErrNetworkIdMismatch,
},
{
- code: StatusMsg, data: statusMsgData{ProtocolVersion, NetworkId, td, currentBlock, common.Hash{3}},
+ code: StatusMsg, data: statusMsgData{ProtocolVersion, NetworkId, *td, currentBlock, common.Hash{3}},
wantErrorCode: ErrGenesisBlockMismatch,
},
}
for _, test := range tests {
- // first outgoing msg should be StatusMsg.
- err := p2p.ExpectMsg(eth, StatusMsg, &statusMsgData{
- ProtocolVersion: ProtocolVersion,
- NetworkId: NetworkId,
- TD: td,
- CurrentBlock: currentBlock,
- GenesisBlock: genesis,
- })
- if err != nil {
- t.Fatalf("incorrect outgoing status: %v", err)
- }
-
+ eth.handshake(t, false)
// the send call might hang until reset because
// the protocol might not read the payload.
go p2p.Send(eth, test.code, test.data)
@@ -216,3 +225,73 @@ func TestStatusMsgErrors(t *testing.T) {
go eth.run()
}
}
+
+func TestNewBlockMsg(t *testing.T) {
+ logInit()
+ eth := newEth(t)
+ eth.blockPool.addBlock = func(block *types.Block, peerId string) (err error) {
+ fmt.Printf("Add Block: %v\n", block)
+ return
+ }
+
+ var disconnected bool
+ eth.blockPool.removePeer = func(peerId string) {
+ fmt.Printf("peer <%s> is disconnected\n", peerId)
+ disconnected = true
+ }
+
+ go eth.run()
+
+ eth.handshake(t, true)
+ err := p2p.ExpectMsg(eth, TxMsg, []interface{}{})
+ if err != nil {
+ t.Errorf("transactions expected, got %v", err)
+ }
+
+ var tds = make(chan *big.Int)
+ eth.blockPool.addPeer = func(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool, suspended bool) {
+ tds <- td
+ return
+ }
+
+ var delay = 1 * time.Second
+ // eth.reset()
+ block := types.NewBlock(common.Hash{1}, common.Address{1}, common.Hash{1}, common.Big1, 1, "extra")
+
+ go p2p.Send(eth, NewBlockMsg, &newBlockMsgData{Block: block})
+ timer := time.After(delay)
+
+ select {
+ case td := <-tds:
+ if td.Cmp(common.Big0) != 0 {
+ t.Errorf("incorrect td %v, expected %v", td, common.Big0)
+ }
+ case <-timer:
+ t.Errorf("no td recorded after %v", delay)
+ return
+ case err := <-eth.quit:
+ t.Errorf("no error expected, got %v", err)
+ return
+ }
+
+ go p2p.Send(eth, NewBlockMsg, &newBlockMsgData{block, common.Big2})
+ timer = time.After(delay)
+
+ select {
+ case td := <-tds:
+ if td.Cmp(common.Big2) != 0 {
+ t.Errorf("incorrect td %v, expected %v", td, common.Big2)
+ }
+ case <-timer:
+ t.Errorf("no td recorded after %v", delay)
+ return
+ case err := <-eth.quit:
+ t.Errorf("no error expected, got %v", err)
+ return
+ }
+
+ go p2p.Send(eth, NewBlockMsg, []interface{}{})
+ // Block.DecodeRLP: validation failed: header is nil
+ eth.checkError(ErrDecode, delay)
+
+}