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

Commit

Permalink
Fix: unbounded alloc and slice out of bounds crashes
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ShimmerGlass committed Jul 21, 2020
1 parent 78f7a6e commit d6cb793
Showing 1 changed file with 24 additions and 12 deletions.
36 changes: 24 additions & 12 deletions lib/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type Logger interface {
}

const (
messageMaxSize = 2048

PROTOCOL_VERSION_0 = 0
PROTOCOL_VERSION_1 = 1

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

if length < 8 {
return nil, errors.New(fmt.Sprintf("Wrong length: %d < 8", length))
return nil, fmt.Errorf("Wrong length: %d < 8", length)
}
if length > messageMaxSize {
return nil, fmt.Errorf("Wrong length: %d > %d", length, messageMaxSize)
}
toread := make([]byte, length-8)
err = binary.Read(rdr, binary.BigEndian, toread)
Expand All @@ -545,7 +550,7 @@ func Decode(rdr io.Reader) (PDU, error) {
switch pduType {
case PDU_ID_SERIAL_NOTIFY:
if len(toread) != 4 {
return nil, errors.New(fmt.Sprintf("Wrong length for Serial Notify PDU: %d != 4", len(toread)))
return nil, fmt.Errorf("Wrong length for Serial Notify PDU: %d != 4", len(toread))
}
serial := binary.BigEndian.Uint32(toread)
return &PDUSerialNotify{
Expand All @@ -555,7 +560,7 @@ func Decode(rdr io.Reader) (PDU, error) {
}, nil
case PDU_ID_SERIAL_QUERY:
if len(toread) != 4 {
return nil, errors.New(fmt.Sprintf("Wrong length for Serial Query PDU: %d != 4", len(toread)))
return nil, fmt.Errorf("Wrong length for Serial Query PDU: %d != 4", len(toread))
}
serial := binary.BigEndian.Uint32(toread)
return &PDUSerialQuery{
Expand All @@ -565,22 +570,22 @@ func Decode(rdr io.Reader) (PDU, error) {
}, nil
case PDU_ID_RESET_QUERY:
if len(toread) != 0 {
return nil, errors.New(fmt.Sprintf("Wrong length for Reset Query PDU: %d != 0", len(toread)))
return nil, fmt.Errorf("Wrong length for Reset Query PDU: %d != 0", len(toread))
}
return &PDUResetQuery{
Version: pver,
}, nil
case PDU_ID_CACHE_RESPONSE:
if len(toread) != 0 {
return nil, errors.New(fmt.Sprintf("Wrong length for Cache Response PDU: %d != 0", len(toread)))
return nil, fmt.Errorf("Wrong length for Cache Response PDU: %d != 0", len(toread))
}
return &PDUCacheResponse{
Version: pver,
SessionId: sessionId,
}, nil
case PDU_ID_IPV4_PREFIX:
if len(toread) != 12 {
return nil, errors.New(fmt.Sprintf("Wrong length for IPv4 Prefix PDU: %d != 12", len(toread)))
return nil, fmt.Errorf("Wrong length for IPv4 Prefix PDU: %d != 12", len(toread))
}
prefixLen := int(toread[1])
ip := toread[4:8]
Expand All @@ -598,7 +603,7 @@ func Decode(rdr io.Reader) (PDU, error) {
}, nil
case PDU_ID_IPV6_PREFIX:
if len(toread) != 24 {
return nil, errors.New(fmt.Sprintf("Wrong length for IPv6 Prefix PDU: %d != 24", len(toread)))
return nil, fmt.Errorf("Wrong length for IPv6 Prefix PDU: %d != 24", len(toread))
}
prefixLen := int(toread[1])
ip := toread[4:20]
Expand All @@ -616,7 +621,7 @@ func Decode(rdr io.Reader) (PDU, error) {
}, nil
case PDU_ID_END_OF_DATA:
if len(toread) != 4 && len(toread) != 16 {
return nil, errors.New(fmt.Sprintf("Wrong length for End of Data PDU: %d != 4 or != 16", len(toread)))
return nil, fmt.Errorf("Wrong length for End of Data PDU: %d != 4 or != 16", len(toread))
}

var serial uint32
Expand All @@ -642,14 +647,14 @@ func Decode(rdr io.Reader) (PDU, error) {
}, nil
case PDU_ID_CACHE_RESET:
if len(toread) != 0 {
return nil, errors.New(fmt.Sprintf("Wrong length for Cache Reset PDU: %d != 0", len(toread)))
return nil, fmt.Errorf("Wrong length for Cache Reset PDU: %d != 0", len(toread))
}
return &PDUCacheReset{
Version: pver,
}, nil
case PDU_ID_ROUTER_KEY:
if len(toread) != 28 {
return nil, errors.New(fmt.Sprintf("Wrong length for Router Key PDU: %d < 8", len(toread)))
return nil, fmt.Errorf("Wrong length for Router Key PDU: %d < 8", len(toread))
}
asn := binary.BigEndian.Uint32(toread[20:24])
spki := binary.BigEndian.Uint32(toread[24:28])
Expand All @@ -663,11 +668,19 @@ func Decode(rdr io.Reader) (PDU, error) {
}, nil
case PDU_ID_ERROR_REPORT:
if len(toread) < 8 {
return nil, errors.New(fmt.Sprintf("Wrong length for Error Report PDU: %d < 8", len(toread)))
return nil, fmt.Errorf("Wrong length for Error Report PDU: %d < 8", len(toread))
}
lenPdu := binary.BigEndian.Uint32(toread[0:4])
if len(toread) < int(lenPdu)+8 {
return nil, fmt.Errorf("Wrong length for Error Report PDU: %d < %d", len(toread), lenPdu+4)
}
errPdu := toread[4 : lenPdu+4]
lenErrText := binary.BigEndian.Uint32(toread[lenPdu+4 : lenPdu+8])
// int casting for each value is needed here to prevent an uint32 overflow that could result in
// upper bound being lower than lower bound causing a crash
if len(toread) < int(lenPdu)+8+int(lenErrText) {
return nil, fmt.Errorf("Wrong length for Error Report PDU: %d < %d", len(toread), lenPdu+8+lenErrText)
}
errMsg := string(toread[lenPdu+8 : lenPdu+8+lenErrText])
return &PDUErrorReport{
Version: pver,
Expand All @@ -678,5 +691,4 @@ func Decode(rdr io.Reader) (PDU, error) {
default:
return nil, errors.New("Could not decode packet")
}
return nil, nil
}

0 comments on commit d6cb793

Please sign in to comment.