Skip to content
This repository was archived by the owner on Feb 29, 2024. It is now read-only.

Commit d6cb793

Browse files
committed
Fix: unbounded alloc and slice out of bounds crashes
In rtrlib.Decode(): * Now check the message length is not greater than a hardcoded limit (2048) to prevent unbounded memory allocations * Fix a few unchecked slice accesses that could result in crashes with the right payload in the PDU_ID_ERROR_REPORT case.
1 parent 78f7a6e commit d6cb793

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

lib/structs.go

+24-12
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ type Logger interface {
1919
}
2020

2121
const (
22+
messageMaxSize = 2048
23+
2224
PROTOCOL_VERSION_0 = 0
2325
PROTOCOL_VERSION_1 = 1
2426

@@ -534,7 +536,10 @@ func Decode(rdr io.Reader) (PDU, error) {
534536
}
535537

536538
if length < 8 {
537-
return nil, errors.New(fmt.Sprintf("Wrong length: %d < 8", length))
539+
return nil, fmt.Errorf("Wrong length: %d < 8", length)
540+
}
541+
if length > messageMaxSize {
542+
return nil, fmt.Errorf("Wrong length: %d > %d", length, messageMaxSize)
538543
}
539544
toread := make([]byte, length-8)
540545
err = binary.Read(rdr, binary.BigEndian, toread)
@@ -545,7 +550,7 @@ func Decode(rdr io.Reader) (PDU, error) {
545550
switch pduType {
546551
case PDU_ID_SERIAL_NOTIFY:
547552
if len(toread) != 4 {
548-
return nil, errors.New(fmt.Sprintf("Wrong length for Serial Notify PDU: %d != 4", len(toread)))
553+
return nil, fmt.Errorf("Wrong length for Serial Notify PDU: %d != 4", len(toread))
549554
}
550555
serial := binary.BigEndian.Uint32(toread)
551556
return &PDUSerialNotify{
@@ -555,7 +560,7 @@ func Decode(rdr io.Reader) (PDU, error) {
555560
}, nil
556561
case PDU_ID_SERIAL_QUERY:
557562
if len(toread) != 4 {
558-
return nil, errors.New(fmt.Sprintf("Wrong length for Serial Query PDU: %d != 4", len(toread)))
563+
return nil, fmt.Errorf("Wrong length for Serial Query PDU: %d != 4", len(toread))
559564
}
560565
serial := binary.BigEndian.Uint32(toread)
561566
return &PDUSerialQuery{
@@ -565,22 +570,22 @@ func Decode(rdr io.Reader) (PDU, error) {
565570
}, nil
566571
case PDU_ID_RESET_QUERY:
567572
if len(toread) != 0 {
568-
return nil, errors.New(fmt.Sprintf("Wrong length for Reset Query PDU: %d != 0", len(toread)))
573+
return nil, fmt.Errorf("Wrong length for Reset Query PDU: %d != 0", len(toread))
569574
}
570575
return &PDUResetQuery{
571576
Version: pver,
572577
}, nil
573578
case PDU_ID_CACHE_RESPONSE:
574579
if len(toread) != 0 {
575-
return nil, errors.New(fmt.Sprintf("Wrong length for Cache Response PDU: %d != 0", len(toread)))
580+
return nil, fmt.Errorf("Wrong length for Cache Response PDU: %d != 0", len(toread))
576581
}
577582
return &PDUCacheResponse{
578583
Version: pver,
579584
SessionId: sessionId,
580585
}, nil
581586
case PDU_ID_IPV4_PREFIX:
582587
if len(toread) != 12 {
583-
return nil, errors.New(fmt.Sprintf("Wrong length for IPv4 Prefix PDU: %d != 12", len(toread)))
588+
return nil, fmt.Errorf("Wrong length for IPv4 Prefix PDU: %d != 12", len(toread))
584589
}
585590
prefixLen := int(toread[1])
586591
ip := toread[4:8]
@@ -598,7 +603,7 @@ func Decode(rdr io.Reader) (PDU, error) {
598603
}, nil
599604
case PDU_ID_IPV6_PREFIX:
600605
if len(toread) != 24 {
601-
return nil, errors.New(fmt.Sprintf("Wrong length for IPv6 Prefix PDU: %d != 24", len(toread)))
606+
return nil, fmt.Errorf("Wrong length for IPv6 Prefix PDU: %d != 24", len(toread))
602607
}
603608
prefixLen := int(toread[1])
604609
ip := toread[4:20]
@@ -616,7 +621,7 @@ func Decode(rdr io.Reader) (PDU, error) {
616621
}, nil
617622
case PDU_ID_END_OF_DATA:
618623
if len(toread) != 4 && len(toread) != 16 {
619-
return nil, errors.New(fmt.Sprintf("Wrong length for End of Data PDU: %d != 4 or != 16", len(toread)))
624+
return nil, fmt.Errorf("Wrong length for End of Data PDU: %d != 4 or != 16", len(toread))
620625
}
621626

622627
var serial uint32
@@ -642,14 +647,14 @@ func Decode(rdr io.Reader) (PDU, error) {
642647
}, nil
643648
case PDU_ID_CACHE_RESET:
644649
if len(toread) != 0 {
645-
return nil, errors.New(fmt.Sprintf("Wrong length for Cache Reset PDU: %d != 0", len(toread)))
650+
return nil, fmt.Errorf("Wrong length for Cache Reset PDU: %d != 0", len(toread))
646651
}
647652
return &PDUCacheReset{
648653
Version: pver,
649654
}, nil
650655
case PDU_ID_ROUTER_KEY:
651656
if len(toread) != 28 {
652-
return nil, errors.New(fmt.Sprintf("Wrong length for Router Key PDU: %d < 8", len(toread)))
657+
return nil, fmt.Errorf("Wrong length for Router Key PDU: %d < 8", len(toread))
653658
}
654659
asn := binary.BigEndian.Uint32(toread[20:24])
655660
spki := binary.BigEndian.Uint32(toread[24:28])
@@ -663,11 +668,19 @@ func Decode(rdr io.Reader) (PDU, error) {
663668
}, nil
664669
case PDU_ID_ERROR_REPORT:
665670
if len(toread) < 8 {
666-
return nil, errors.New(fmt.Sprintf("Wrong length for Error Report PDU: %d < 8", len(toread)))
671+
return nil, fmt.Errorf("Wrong length for Error Report PDU: %d < 8", len(toread))
667672
}
668673
lenPdu := binary.BigEndian.Uint32(toread[0:4])
674+
if len(toread) < int(lenPdu)+8 {
675+
return nil, fmt.Errorf("Wrong length for Error Report PDU: %d < %d", len(toread), lenPdu+4)
676+
}
669677
errPdu := toread[4 : lenPdu+4]
670678
lenErrText := binary.BigEndian.Uint32(toread[lenPdu+4 : lenPdu+8])
679+
// int casting for each value is needed here to prevent an uint32 overflow that could result in
680+
// upper bound being lower than lower bound causing a crash
681+
if len(toread) < int(lenPdu)+8+int(lenErrText) {
682+
return nil, fmt.Errorf("Wrong length for Error Report PDU: %d < %d", len(toread), lenPdu+8+lenErrText)
683+
}
671684
errMsg := string(toread[lenPdu+8 : lenPdu+8+lenErrText])
672685
return &PDUErrorReport{
673686
Version: pver,
@@ -678,5 +691,4 @@ func Decode(rdr io.Reader) (PDU, error) {
678691
default:
679692
return nil, errors.New("Could not decode packet")
680693
}
681-
return nil, nil
682694
}

0 commit comments

Comments
 (0)