Skip to content

Commit 817a3fb

Browse files
authored
p2p/enode: avoid crashing for invalid IP (#21981)
The database panicked for invalid IPs. This is usually no problem because all code paths leading to node DB access verify the IP, but it's dangerous because improper validation can turn this panic into a DoS vulnerability. The quick fix here is to just turn database accesses using invalid IP into a noop. This isn't great, but I'm planning to remove the node DB for discv5 long-term, so it should be fine to have this quick fix for half a year. Fixes #21849
1 parent f935b1d commit 817a3fb

File tree

1 file changed

+28
-0
lines changed

1 file changed

+28
-0
lines changed

p2p/enode/nodedb.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ const (
6161
dbVersion = 9
6262
)
6363

64+
var (
65+
errInvalidIP = errors.New("invalid IP")
66+
)
67+
6468
var zeroIP = make(net.IP, 16)
6569

6670
// DB is the node database, storing previously seen nodes and any collected metadata about
@@ -359,43 +363,67 @@ func (db *DB) expireNodes() {
359363
// LastPingReceived retrieves the time of the last ping packet received from
360364
// a remote node.
361365
func (db *DB) LastPingReceived(id ID, ip net.IP) time.Time {
366+
if ip = ip.To16(); ip == nil {
367+
return time.Time{}
368+
}
362369
return time.Unix(db.fetchInt64(nodeItemKey(id, ip, dbNodePing)), 0)
363370
}
364371

365372
// UpdateLastPingReceived updates the last time we tried contacting a remote node.
366373
func (db *DB) UpdateLastPingReceived(id ID, ip net.IP, instance time.Time) error {
374+
if ip = ip.To16(); ip == nil {
375+
return errInvalidIP
376+
}
367377
return db.storeInt64(nodeItemKey(id, ip, dbNodePing), instance.Unix())
368378
}
369379

370380
// LastPongReceived retrieves the time of the last successful pong from remote node.
371381
func (db *DB) LastPongReceived(id ID, ip net.IP) time.Time {
382+
if ip = ip.To16(); ip == nil {
383+
return time.Time{}
384+
}
372385
// Launch expirer
373386
db.ensureExpirer()
374387
return time.Unix(db.fetchInt64(nodeItemKey(id, ip, dbNodePong)), 0)
375388
}
376389

377390
// UpdateLastPongReceived updates the last pong time of a node.
378391
func (db *DB) UpdateLastPongReceived(id ID, ip net.IP, instance time.Time) error {
392+
if ip = ip.To16(); ip == nil {
393+
return errInvalidIP
394+
}
379395
return db.storeInt64(nodeItemKey(id, ip, dbNodePong), instance.Unix())
380396
}
381397

382398
// FindFails retrieves the number of findnode failures since bonding.
383399
func (db *DB) FindFails(id ID, ip net.IP) int {
400+
if ip = ip.To16(); ip == nil {
401+
return 0
402+
}
384403
return int(db.fetchInt64(nodeItemKey(id, ip, dbNodeFindFails)))
385404
}
386405

387406
// UpdateFindFails updates the number of findnode failures since bonding.
388407
func (db *DB) UpdateFindFails(id ID, ip net.IP, fails int) error {
408+
if ip = ip.To16(); ip == nil {
409+
return errInvalidIP
410+
}
389411
return db.storeInt64(nodeItemKey(id, ip, dbNodeFindFails), int64(fails))
390412
}
391413

392414
// FindFailsV5 retrieves the discv5 findnode failure counter.
393415
func (db *DB) FindFailsV5(id ID, ip net.IP) int {
416+
if ip = ip.To16(); ip == nil {
417+
return 0
418+
}
394419
return int(db.fetchInt64(v5Key(id, ip, dbNodeFindFails)))
395420
}
396421

397422
// UpdateFindFailsV5 stores the discv5 findnode failure counter.
398423
func (db *DB) UpdateFindFailsV5(id ID, ip net.IP, fails int) error {
424+
if ip = ip.To16(); ip == nil {
425+
return errInvalidIP
426+
}
399427
return db.storeInt64(v5Key(id, ip, dbNodeFindFails), int64(fails))
400428
}
401429

0 commit comments

Comments
 (0)