diff --git a/core/blockchain.go b/core/blockchain.go index ea26fa0345..cc0ee57d98 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1524,6 +1524,12 @@ func (bc *BlockChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []com return bc.hc.GetBlockHashesFromHash(hash, max) } +// GetAncestorBlockHashFromHash retrieves the block hash for the ancestor of a given +// hash, fetching towards the genesis block. +func (bc *BlockChain) GetAncestorBlockHashFromHash(hash common.Hash, max uint64) common.Hash { + return bc.hc.GetAncestorBlockHashFromHash(hash, max) +} + // GetHeaderByNumber retrieves a block header from the database by number, // caching it (associated with its hash) if found. func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header { diff --git a/core/headerchain.go b/core/headerchain.go index 2ac0cccc72..545bd1ae09 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -307,6 +307,27 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co return chain } +// GetAncestorBlockHashFromHash retrieves the block hash for the ancestor of a given +// hash, fetching towards the genesis block. +func (hc *HeaderChain) GetAncestorBlockHashFromHash(hash common.Hash, max uint64) common.Hash { + // Get the origin header from which to fetch + header := hc.GetHeaderByHash(hash) + if header == nil { + return common.Hash{} + } + // Iterate the headers until enough is collected or the genesis reached + next := common.Hash{} + for i := uint64(0); i < max; i++ { + next = header.ParentHash + if header = hc.GetHeader(next, header.Number.Uint64()-1); header == nil { + return common.Hash{} + } + if header.Number.Sign() == 0 { + return common.Hash{} + } + } + return next +} // GetTd retrieves a block's total difficulty in the canonical chain from the // database by hash and number, caching it if found. func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { diff --git a/eth/handler.go b/eth/handler.go index 918d71088d..1c071ee415 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -387,7 +387,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { unknown = true } else { if header := pm.blockchain.GetHeaderByNumber(next); header != nil { - if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash { + if pm.blockchain.GetAncestorBlockHashFromHash(header.Hash(), query.Skip+1) == query.Origin.Hash { query.Origin.Hash = header.Hash() } else { unknown = true diff --git a/les/handler.go b/les/handler.go index 38f810d721..c6fd4a89bb 100644 --- a/les/handler.go +++ b/les/handler.go @@ -84,6 +84,7 @@ type BlockChain interface { Rollback(chain []common.Hash) GetHeaderByNumber(number uint64) *types.Header GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash + GetAncestorBlockHashFromHash(hash common.Hash, max uint64) common.Hash Genesis() *types.Block SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription } @@ -466,7 +467,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { unknown = true } else { if header := pm.blockchain.GetHeaderByNumber(next); header != nil { - if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash { + if pm.blockchain.GetAncestorBlockHashFromHash(header.Hash(), query.Skip+1) == query.Origin.Hash { query.Origin.Hash = header.Hash() } else { unknown = true diff --git a/les/handler_test.go b/les/handler_test.go index 31aad3ed45..fde7c2a11f 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -75,6 +75,11 @@ func testGetBlockHeaders(t *testing.T, protocol int) { &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1}, []common.Hash{bc.GetBlockByNumber(limit / 2).Hash()}, }, + // Overflow attack + { + &getBlockHeadersData{Origin: hashOrNumber{Hash:bc.GetBlockByNumber(1).Hash()}, Amount: 1,Skip:0xFFFFFFFFFFFFFFFF}, + []common.Hash{}, + }, // Multiple headers should be retrievable in both directions { &getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3}, diff --git a/light/lightchain.go b/light/lightchain.go index 9d0a4e4f73..cdad71fcc4 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -433,6 +433,12 @@ func (self *LightChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []c return self.hc.GetBlockHashesFromHash(hash, max) } +// GetAncestorBlockHashFromHash retrieves the block hash for the ancestor of a given +// hash, fetching towards the genesis block. +func (self *LightChain) GetAncestorBlockHashFromHash(hash common.Hash, max uint64) common.Hash{ + return self.hc.GetAncestorBlockHashFromHash(hash, max) +} + // GetHeaderByNumber retrieves a block header from the database by number, // caching it (associated with its hash) if found. func (self *LightChain) GetHeaderByNumber(number uint64) *types.Header {