diff --git a/polyamide/device/send.go b/polyamide/device/send.go index 1a50ee06..3f677e7c 100644 --- a/polyamide/device/send.go +++ b/polyamide/device/send.go @@ -249,6 +249,7 @@ func (device *Device) RoutineReadFromTUN() { } tce := device.GetTCElement() tce.Buffer = bufs[i] + tce.Packet = bufs[i][offset : offset+sizes[i]] tcBufs = append(tcBufs, tce) bufs[i] = device.GetMessageBuffer() diff --git a/polyamide/device/traffic_control.go b/polyamide/device/traffic_control.go index 04147042..6ecb48b9 100644 --- a/polyamide/device/traffic_control.go +++ b/polyamide/device/traffic_control.go @@ -109,8 +109,7 @@ func (device *Device) TCBatch(batch []*TCElement, tcs *TCState) { for i, elem := range batch { // process TC Filters act := TcPass - elem.ParsePacket() - if !elem.Validate() { + if !elem.ParsePacket() || !elem.Validate() { device.Log.Errorf("Found malformed packet, dropping packet") act = TcDrop } else { diff --git a/polyamide/device/traffic_manip.go b/polyamide/device/traffic_manip.go index 23061fc4..89d956eb 100644 --- a/polyamide/device/traffic_manip.go +++ b/polyamide/device/traffic_manip.go @@ -20,10 +20,25 @@ func (elem *TCElement) InitPacket(ver int, len uint16) { elem.SetLength(len) } -func (elem *TCElement) ParsePacket() { - elem.Packet = elem.Buffer[MessageTransportHeaderSize:] +func (elem *TCElement) ParsePacket() bool { + if elem == nil { + return false + } + if len(elem.Packet) == 0 { + if elem.Buffer == nil { + return false + } + elem.Packet = elem.Buffer[MessageTransportHeaderSize:] + } + if !elem.hasPacketHeader() { + return false + } l := elem.GetLength() - elem.Packet = elem.Buffer[MessageTransportHeaderSize : MessageTransportHeaderSize+l] + if int(l) > len(elem.Packet) { + return false + } + elem.Packet = elem.Packet[:l] + return true } func (elem *TCElement) Incoming() bool { @@ -137,6 +152,9 @@ func (elem *TCElement) Validate() bool { if elem == nil || len(elem.Packet) == 0 { return false } + if !elem.hasPacketHeader() { + return false + } ver := elem.GetIPVersion() if ver == 4 { if elem.GetLength() < ipv4.HeaderLen { @@ -154,6 +172,19 @@ func (elem *TCElement) Validate() bool { return true } +func (elem *TCElement) hasPacketHeader() bool { + if elem == nil || len(elem.Packet) < PolyHeaderSize { + return false + } + ver := elem.GetIPVersion() + if ver == 4 { + return len(elem.Packet) >= ipv4.HeaderLen + } else if ver == 6 { + return len(elem.Packet) >= ipv6.HeaderLen + } + return true +} + func (elem *TCElement) TTLBytes() []byte { if elem.GetIPVersion() == 4 { return elem.Packet[8:9] diff --git a/polyamide/device/traffic_manip_test.go b/polyamide/device/traffic_manip_test.go new file mode 100644 index 00000000..bf9e3ad6 --- /dev/null +++ b/polyamide/device/traffic_manip_test.go @@ -0,0 +1,41 @@ +package device + +import ( + "encoding/binary" + "testing" +) + +func TestParsePacketRejectsLengthBeyondReadBuffer(t *testing.T) { + var buf [MaxMessageSize]byte + packet := buf[MessageTransportHeaderSize : MessageTransportHeaderSize+2016] + packet[0] = 6 << 4 + binary.BigEndian.PutUint16(packet[IPv6offsetPayloadLength:IPv6offsetPayloadLength+2], 2010) + + elem := &TCElement{ + Buffer: &buf, + Packet: packet, + } + + if elem.ParsePacket() { + t.Fatal("expected oversized packet to be rejected") + } +} + +func TestParsePacketTrimsToAdvertisedLength(t *testing.T) { + var buf [MaxMessageSize]byte + packet := buf[MessageTransportHeaderSize : MessageTransportHeaderSize+128] + packet[0] = 6 << 4 + binary.BigEndian.PutUint16(packet[IPv6offsetPayloadLength:IPv6offsetPayloadLength+2], 8) + + elem := &TCElement{ + Buffer: &buf, + Packet: packet, + } + + if !elem.ParsePacket() { + t.Fatal("expected valid packet to parse") + } + if len(elem.Packet) != 48 { + t.Fatalf("expected packet length 48, got %d", len(elem.Packet)) + } +}