aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/types/block.go26
-rw-r--r--eth/fetcher/fetcher.go8
-rw-r--r--eth/handler.go3
-rw-r--r--eth/protocol.go13
-rw-r--r--les/handler.go4
-rw-r--r--les/protocol.go8
6 files changed, 57 insertions, 5 deletions
diff --git a/core/types/block.go b/core/types/block.go
index f754c3c48..b0ec7fc77 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -19,6 +19,7 @@ package types
import (
"encoding/binary"
+ "fmt"
"io"
"math/big"
"reflect"
@@ -110,6 +111,25 @@ func (h *Header) Size() common.StorageSize {
return headerSize + common.StorageSize(len(h.Extra)+(h.Difficulty.BitLen()+h.Number.BitLen())/8)
}
+// SanityCheck checks a few basic things -- these checks are way beyond what
+// any 'sane' production values should hold, and can mainly be used to prevent
+// that the unbounded fields are stuffed with junk data to add processing
+// overhead
+func (h *Header) SanityCheck() error {
+ if h.Number != nil && !h.Number.IsUint64() {
+ return fmt.Errorf("too large block number: bitlen %d", h.Number.BitLen())
+ }
+ if h.Difficulty != nil {
+ if diffLen := h.Difficulty.BitLen(); diffLen > 80 {
+ return fmt.Errorf("too large block difficulty: bitlen %d", diffLen)
+ }
+ }
+ if eLen := len(h.Extra); eLen > 100*1024 {
+ return fmt.Errorf("too large block extradata: size %d", eLen)
+ }
+ return nil
+}
+
func rlpHash(x interface{}) (h common.Hash) {
hw := sha3.NewLegacyKeccak256()
rlp.Encode(hw, x)
@@ -316,6 +336,12 @@ func (b *Block) Size() common.StorageSize {
return common.StorageSize(c)
}
+// SanityCheck can be used to prevent that unbounded fields are
+// stuffed with junk data to add processing overhead
+func (b *Block) SanityCheck() error {
+ return b.header.SanityCheck()
+}
+
type writeCounter common.StorageSize
func (c *writeCounter) Write(b []byte) (int, error) {
diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go
index 94f05f967..28c532d9b 100644
--- a/eth/fetcher/fetcher.go
+++ b/eth/fetcher/fetcher.go
@@ -685,7 +685,7 @@ func (f *Fetcher) forgetHash(hash common.Hash) {
// Remove all pending announces and decrement DOS counters
for _, announce := range f.announced[hash] {
f.announces[announce.origin]--
- if f.announces[announce.origin] == 0 {
+ if f.announces[announce.origin] <= 0 {
delete(f.announces, announce.origin)
}
}
@@ -696,7 +696,7 @@ func (f *Fetcher) forgetHash(hash common.Hash) {
// Remove any pending fetches and decrement the DOS counters
if announce := f.fetching[hash]; announce != nil {
f.announces[announce.origin]--
- if f.announces[announce.origin] == 0 {
+ if f.announces[announce.origin] <= 0 {
delete(f.announces, announce.origin)
}
delete(f.fetching, hash)
@@ -705,7 +705,7 @@ func (f *Fetcher) forgetHash(hash common.Hash) {
// Remove any pending completion requests and decrement the DOS counters
for _, announce := range f.fetched[hash] {
f.announces[announce.origin]--
- if f.announces[announce.origin] == 0 {
+ if f.announces[announce.origin] <= 0 {
delete(f.announces, announce.origin)
}
}
@@ -714,7 +714,7 @@ func (f *Fetcher) forgetHash(hash common.Hash) {
// Remove any pending completions and decrement the DOS counters
if announce := f.completing[hash]; announce != nil {
f.announces[announce.origin]--
- if f.announces[announce.origin] == 0 {
+ if f.announces[announce.origin] <= 0 {
delete(f.announces, announce.origin)
}
delete(f.completing, hash)
diff --git a/eth/handler.go b/eth/handler.go
index db6901a23..fe9f8b53b 100644
--- a/eth/handler.go
+++ b/eth/handler.go
@@ -697,6 +697,9 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if err := msg.Decode(&request); err != nil {
return errResp(ErrDecode, "%v: %v", msg, err)
}
+ if err := request.sanityCheck(); err != nil {
+ return err
+ }
request.Block.ReceivedAt = msg.ReceivedAt
request.Block.ReceivedFrom = p
diff --git a/eth/protocol.go b/eth/protocol.go
index 497ba4c59..5beb562f8 100644
--- a/eth/protocol.go
+++ b/eth/protocol.go
@@ -173,6 +173,19 @@ type newBlockData struct {
TD *big.Int
}
+// sanityCheck verifies that the values are reasonable, as a DoS protection
+func (request *newBlockData) sanityCheck() error {
+ if err := request.Block.SanityCheck(); err != nil {
+ return err
+ }
+ //TD at mainnet block #7753254 is 76 bits. If it becomes 100 million times
+ // larger, it will still fit within 100 bits
+ if tdlen := request.TD.BitLen(); tdlen > 100 {
+ return fmt.Errorf("too large block TD: bitlen %d", tdlen)
+ }
+ return nil
+}
+
// blockBody represents the data content of a single block.
type blockBody struct {
Transactions []*types.Transaction // Transactions contained within a block
diff --git a/les/handler.go b/les/handler.go
index d9d07f014..ea2ec3324 100644
--- a/les/handler.go
+++ b/les/handler.go
@@ -442,7 +442,9 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if err := msg.Decode(&req); err != nil {
return errResp(ErrDecode, "%v: %v", msg, err)
}
-
+ if err := req.sanityCheck(); err != nil {
+ return err
+ }
update, size := req.Update.decode()
if p.rejectUpdate(size) {
return errResp(ErrRequestRejected, "")
diff --git a/les/protocol.go b/les/protocol.go
index ebf581473..5fdf32b74 100644
--- a/les/protocol.go
+++ b/les/protocol.go
@@ -149,6 +149,14 @@ type announceData struct {
Update keyValueList
}
+// sanityCheck verifies that the values are reasonable, as a DoS protection
+func (a *announceData) sanityCheck() error {
+ if tdlen := a.Td.BitLen(); tdlen > 100 {
+ return fmt.Errorf("too large block TD: bitlen %d", tdlen)
+ }
+ return nil
+}
+
// sign adds a signature to the block announcement by the given privKey
func (a *announceData) sign(privKey *ecdsa.PrivateKey) {
rlp, _ := rlp.EncodeToBytes(announceBlock{a.Hash, a.Number, a.Td})