diff options
author | Ghanan Gowripalan <ghanan@google.com> | 2020-04-07 13:35:58 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-04-07 13:37:10 -0700 |
commit | 6db55a5bd8933b217d285018ed2187812ebae6ef (patch) | |
tree | df159e12ec6bf03082b82e2cab5ab5aba3e100de /pkg/tcpip/network/ipv6 | |
parent | 71770e56629339c9853466e994b78b172bc668a9 (diff) |
Require that IPv6 headers be in the first fragment
Test:
- header_test.TestIPv6ExtHdrIter
- ipv6_test.TestReceiveIPv6Fragments
Updates #2197, #2333
PiperOrigin-RevId: 305330178
Diffstat (limited to 'pkg/tcpip/network/ipv6')
-rw-r--r-- | pkg/tcpip/network/ipv6/ipv6.go | 50 | ||||
-rw-r--r-- | pkg/tcpip/network/ipv6/ipv6_test.go | 2 |
2 files changed, 50 insertions, 2 deletions
diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go index a815b4d9b..331b0817b 100644 --- a/pkg/tcpip/network/ipv6/ipv6.go +++ b/pkg/tcpip/network/ipv6/ipv6.go @@ -270,7 +270,55 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt stack.PacketBuffer) { continue } - rawPayload := it.AsRawHeader() + // Don't consume the iterator if we have the first fragment because we + // will use it to validate that the first fragment holds the upper layer + // header. + rawPayload := it.AsRawHeader(fragmentOffset != 0 /* consume */) + + if fragmentOffset == 0 { + // Check that the iterator ends with a raw payload as the first fragment + // should include all headers up to and including any upper layer + // headers, as per RFC 8200 section 4.5; only upper layer data + // (non-headers) should follow the fragment extension header. + var lastHdr header.IPv6PayloadHeader + + for { + it, done, err := it.Next() + if err != nil { + r.Stats().IP.MalformedPacketsReceived.Increment() + r.Stats().IP.MalformedPacketsReceived.Increment() + return + } + if done { + break + } + + lastHdr = it + } + + // If the last header is a raw header, then the last portion of the IPv6 + // payload is not a known IPv6 extension header. Note, this does not + // mean that the last portion is an upper layer header or not an + // extension header because: + // 1) we do not yet support all extension headers + // 2) we do not validate the upper layer header before reassembling. + // + // This check makes sure that a known IPv6 extension header is not + // present after the Fragment extension header in a non-initial + // fragment. + // + // TODO(#2196): Support IPv6 Authentication and Encapsulated + // Security Payload extension headers. + // TODO(#2333): Validate that the upper layer header is valid. + switch lastHdr.(type) { + case header.IPv6RawPayloadHeader: + default: + r.Stats().IP.MalformedPacketsReceived.Increment() + r.Stats().IP.MalformedFragmentsReceived.Increment() + return + } + } + fragmentPayloadLen := rawPayload.Buf.Size() if fragmentPayloadLen == 0 { // Drop the packet as it's marked as a fragment but has no payload. diff --git a/pkg/tcpip/network/ipv6/ipv6_test.go b/pkg/tcpip/network/ipv6/ipv6_test.go index 37f7e53ce..95e5dbf8e 100644 --- a/pkg/tcpip/network/ipv6/ipv6_test.go +++ b/pkg/tcpip/network/ipv6/ipv6_test.go @@ -1014,7 +1014,7 @@ func TestReceiveIPv6Fragments(t *testing.T) { ), }, }, - expectedPayloads: [][]byte{udpPayload1}, + expectedPayloads: nil, }, { name: "Two fragments with routing header with non-zero segments left across fragments", |