Browse Source

route: don't crash or hang up with corrupted messages

Fixes golang/go#16438.

Change-Id: I2a97e57cae298e8eecdd5637c9e03493a449fc62
Reviewed-on: https://go-review.googlesource.com/25070
Run-TryBot: Mikio Hara <mikioh.mikioh@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Mikio Hara 9 years ago
parent
commit
4d38db7685
6 changed files with 63 additions and 11 deletions
  1. 15 3
      route/address.go
  2. 6 6
      route/interface_freebsd.go
  3. 8 1
      route/interface_openbsd.go
  4. 6 0
      route/message.go
  5. 23 0
      route/message_test.go
  6. 5 1
      route/route_openbsd.go

+ 15 - 3
route/address.go

@@ -234,7 +234,11 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) (
 					return nil, err
 					return nil, err
 				}
 				}
 				as[i] = a
 				as[i] = a
-				b = b[roundup(int(b[0])):]
+				l := roundup(int(b[0]))
+				if len(b) < l {
+					return nil, errMessageTooShort
+				}
+				b = b[l:]
 			case sysAF_INET, sysAF_INET6:
 			case sysAF_INET, sysAF_INET6:
 				af = int(b[1])
 				af = int(b[1])
 				a, err := parseInetAddr(af, b)
 				a, err := parseInetAddr(af, b)
@@ -242,7 +246,11 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) (
 					return nil, err
 					return nil, err
 				}
 				}
 				as[i] = a
 				as[i] = a
-				b = b[roundup(int(b[0])):]
+				l := roundup(int(b[0]))
+				if len(b) < l {
+					return nil, errMessageTooShort
+				}
+				b = b[l:]
 			default:
 			default:
 				l, a, err := fn(af, b)
 				l, a, err := fn(af, b)
 				if err != nil {
 				if err != nil {
@@ -262,7 +270,11 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) (
 				return nil, err
 				return nil, err
 			}
 			}
 			as[i] = a
 			as[i] = a
-			b = b[roundup(int(b[0])):]
+			l := roundup(int(b[0]))
+			if len(b) < l {
+				return nil, errMessageTooShort
+			}
+			b = b[l:]
 		}
 		}
 	}
 	}
 	return as[:], nil
 	return as[:], nil

+ 6 - 6
route/interface_freebsd.go

@@ -13,12 +13,12 @@ func (w *wireFormat) parseInterfaceMessage(typ RIBType, b []byte) (Message, erro
 		extOff = int(nativeEndian.Uint16(b[18:20]))
 		extOff = int(nativeEndian.Uint16(b[18:20]))
 		bodyOff = int(nativeEndian.Uint16(b[16:18]))
 		bodyOff = int(nativeEndian.Uint16(b[16:18]))
 	} else {
 	} else {
-		if len(b) < w.bodyOff {
-			return nil, errMessageTooShort
-		}
 		extOff = w.extOff
 		extOff = w.extOff
 		bodyOff = w.bodyOff
 		bodyOff = w.bodyOff
 	}
 	}
+	if len(b) < extOff || len(b) < bodyOff {
+		return nil, errInvalidMessage
+	}
 	l := int(nativeEndian.Uint16(b[:2]))
 	l := int(nativeEndian.Uint16(b[:2]))
 	if len(b) < l {
 	if len(b) < l {
 		return nil, errInvalidMessage
 		return nil, errInvalidMessage
@@ -53,11 +53,11 @@ func (w *wireFormat) parseInterfaceAddrMessage(typ RIBType, b []byte) (Message,
 		}
 		}
 		bodyOff = int(nativeEndian.Uint16(b[16:18]))
 		bodyOff = int(nativeEndian.Uint16(b[16:18]))
 	} else {
 	} else {
-		if len(b) < w.bodyOff {
-			return nil, errMessageTooShort
-		}
 		bodyOff = w.bodyOff
 		bodyOff = w.bodyOff
 	}
 	}
+	if len(b) < bodyOff {
+		return nil, errInvalidMessage
+	}
 	l := int(nativeEndian.Uint16(b[:2]))
 	l := int(nativeEndian.Uint16(b[:2]))
 	if len(b) < l {
 	if len(b) < l {
 		return nil, errInvalidMessage
 		return nil, errInvalidMessage

+ 8 - 1
route/interface_openbsd.go

@@ -24,7 +24,11 @@ func (*wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) {
 		Addrs:   make([]Addr, sysRTAX_MAX),
 		Addrs:   make([]Addr, sysRTAX_MAX),
 		raw:     b[:l],
 		raw:     b[:l],
 	}
 	}
-	a, err := parseLinkAddr(b[int(nativeEndian.Uint16(b[4:6])):])
+	ll := int(nativeEndian.Uint16(b[4:6]))
+	if len(b) < ll {
+		return nil, errInvalidMessage
+	}
+	a, err := parseLinkAddr(b[ll:])
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -42,6 +46,9 @@ func (*wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, erro
 		return nil, errInvalidMessage
 		return nil, errInvalidMessage
 	}
 	}
 	bodyOff := int(nativeEndian.Uint16(b[4:6]))
 	bodyOff := int(nativeEndian.Uint16(b[4:6]))
+	if len(b) < bodyOff {
+		return nil, errInvalidMessage
+	}
 	m := &InterfaceAddrMessage{
 	m := &InterfaceAddrMessage{
 		Version: int(b[2]),
 		Version: int(b[2]),
 		Type:    int(b[3]),
 		Type:    int(b[3]),

+ 6 - 0
route/message.go

@@ -42,6 +42,12 @@ func ParseRIB(typ RIBType, b []byte) ([]Message, error) {
 	for len(b) > 4 {
 	for len(b) > 4 {
 		nmsgs++
 		nmsgs++
 		l := int(nativeEndian.Uint16(b[:2]))
 		l := int(nativeEndian.Uint16(b[:2]))
+		if l == 0 {
+			return nil, errInvalidMessage
+		}
+		if len(b) < l {
+			return nil, errMessageTooShort
+		}
 		if b[2] != sysRTM_VERSION {
 		if b[2] != sysRTM_VERSION {
 			b = b[l:]
 			b = b[l:]
 			continue
 			continue

+ 23 - 0
route/message_test.go

@@ -93,3 +93,26 @@ func TestMonitorAndParseRIB(t *testing.T) {
 		time.Sleep(200 * time.Millisecond)
 		time.Sleep(200 * time.Millisecond)
 	}
 	}
 }
 }
+
+func TestParseRIBWithFuzz(t *testing.T) {
+	for _, fuzz := range []string{
+		"0\x00\x05\x050000000000000000" +
+			"00000000000000000000" +
+			"00000000000000000000" +
+			"00000000000000000000" +
+			"0000000000000\x02000000" +
+			"00000000",
+		"\x02\x00\x05\f0000000000000000" +
+			"0\x0200000000000000",
+		"\x02\x00\x05\x100000000000000\x1200" +
+			"0\x00\xff\x00",
+		"\x02\x00\x05\f0000000000000000" +
+			"0\x12000\x00\x02\x0000",
+		"\x00\x00\x00\x01\x00",
+		"00000",
+	} {
+		for typ := RIBType(0); typ < 256; typ++ {
+			ParseRIB(typ, []byte(fuzz))
+		}
+	}
+}

+ 5 - 1
route/route_openbsd.go

@@ -19,7 +19,11 @@ func (*wireFormat) parseRouteMessage(_ RIBType, b []byte) (Message, error) {
 		Index:   int(nativeEndian.Uint16(b[6:8])),
 		Index:   int(nativeEndian.Uint16(b[6:8])),
 		raw:     b[:l],
 		raw:     b[:l],
 	}
 	}
-	as, err := parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[int(nativeEndian.Uint16(b[4:6])):])
+	ll := int(nativeEndian.Uint16(b[4:6]))
+	if len(b) < ll {
+		return nil, errInvalidMessage
+	}
+	as, err := parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[ll:])
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}