Report correct pointer value for "bad next header" ICMP error

Because the code handles a bad header as "payload" right up to the last moment
we need to make sure payload handling does not remove the error information.

Fixes #4909

PiperOrigin-RevId: 344141690
This commit is contained in:
Julian Elischer 2020-11-24 15:23:31 -08:00 committed by gVisor bot
parent f90ab60a8a
commit 4da63dc82e
4 changed files with 51 additions and 15 deletions

View File

@ -47,6 +47,11 @@ const (
// IPv6NoNextHeaderIdentifier is the header identifier used to signify the end
// of an IPv6 payload, as per RFC 8200 section 4.7.
IPv6NoNextHeaderIdentifier IPv6ExtensionHeaderIdentifier = 59
// IPv6UnknownExtHdrIdentifier is reserved by IANA.
// https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml#extension-header
// "254 Use for experimentation and testing [RFC3692][RFC4727]"
IPv6UnknownExtHdrIdentifier IPv6ExtensionHeaderIdentifier = 254
)
const (
@ -452,9 +457,11 @@ func (i *IPv6PayloadIterator) AsRawHeader(consume bool) IPv6RawPayloadHeader {
// Since we consume the iterator, we return the payload as is.
buf = i.payload
// Mark i as done.
// Mark i as done, but keep track of where we were for error reporting.
*i = IPv6PayloadIterator{
nextHdrIdentifier: IPv6NoNextHeaderIdentifier,
headerOffset: i.headerOffset,
nextOffset: i.nextOffset,
}
} else {
buf = i.payload.Clone(nil)

View File

@ -34,7 +34,9 @@ import (
)
const (
// ReassembleTimeout controls how long a fragment will be held.
// As per RFC 8200 section 4.5:
//
// If insufficient fragments are received to complete reassembly of a packet
// within 60 seconds of the reception of the first-arriving fragment of that
// packet, reassembly of that packet must be abandoned.
@ -1092,9 +1094,16 @@ func (e *endpoint) handlePacket(pkt *stack.PacketBuffer) {
//
// Which when taken together indicate that an unknown protocol should
// be treated as an unrecognized next header value.
// The location of the Next Header field is in a different place in
// the initial IPv6 header than it is in the extension headers so
// treat it specially.
prevHdrIDOffset := uint32(header.IPv6NextHeaderOffset)
if previousHeaderStart != 0 {
prevHdrIDOffset = previousHeaderStart
}
_ = e.protocol.returnError(&icmpReasonParameterProblem{
code: header.ICMPv6UnknownHeader,
pointer: it.ParseOffset(),
pointer: prevHdrIDOffset,
}, pkt)
default:
panic(fmt.Sprintf("unrecognized result from DeliverTransportPacket = %d", res))
@ -1102,12 +1111,11 @@ func (e *endpoint) handlePacket(pkt *stack.PacketBuffer) {
}
default:
_ = e.protocol.returnError(&icmpReasonParameterProblem{
code: header.ICMPv6UnknownHeader,
pointer: it.ParseOffset(),
}, pkt)
stats.UnknownProtocolRcvdPackets.Increment()
return
// Since the iterator returns IPv6RawPayloadHeader for unknown Extension
// Header IDs this should never happen unless we missed a supported type
// here.
panic(fmt.Sprintf("unrecognized type from it.Next() = %T", extHdr))
}
}
}

View File

@ -51,6 +51,7 @@ const (
fragmentExtHdrID = uint8(header.IPv6FragmentExtHdrIdentifier)
destinationExtHdrID = uint8(header.IPv6DestinationOptionsExtHdrIdentifier)
noNextHdrID = uint8(header.IPv6NoNextHeaderIdentifier)
unknownHdrID = uint8(header.IPv6UnknownExtHdrIdentifier)
extraHeaderReserve = 50
)
@ -572,6 +573,33 @@ func TestReceiveIPv6ExtHdrs(t *testing.T) {
shouldAccept: false,
expectICMP: false,
},
{
name: "unknown next header (first)",
extHdr: func(nextHdr uint8) ([]byte, uint8) {
return []byte{
nextHdr, 0, 63, 4, 1, 2, 3, 4,
}, unknownHdrID
},
shouldAccept: false,
expectICMP: true,
ICMPType: header.ICMPv6ParamProblem,
ICMPCode: header.ICMPv6UnknownHeader,
pointer: header.IPv6NextHeaderOffset,
},
{
name: "unknown next header (not first)",
extHdr: func(nextHdr uint8) ([]byte, uint8) {
return []byte{
unknownHdrID, 0,
63, 4, 1, 2, 3, 4,
}, hopByHopExtHdrID
},
shouldAccept: false,
expectICMP: true,
ICMPType: header.ICMPv6ParamProblem,
ICMPCode: header.ICMPv6UnknownHeader,
pointer: header.IPv6FixedHeaderSize,
},
{
name: "destination with unknown option skippable action",
extHdr: func(nextHdr uint8) ([]byte, uint8) {
@ -754,11 +782,6 @@ func TestReceiveIPv6ExtHdrs(t *testing.T) {
ICMPCode: header.ICMPv6UnknownHeader,
pointer: header.IPv6FixedHeaderSize,
},
{
name: "No next header",
extHdr: func(nextHdr uint8) ([]byte, uint8) { return []byte{}, noNextHdrID },
shouldAccept: false,
},
{
name: "hopbyhop (with skippable unknown) - routing - atomic fragment - destination (with skippable unknown)",
extHdr: func(nextHdr uint8) ([]byte, uint8) {

View File

@ -243,8 +243,6 @@ ALL_TESTS = [
),
PacketimpactTestInfo(
name = "icmpv6_param_problem",
# TODO(b/153485026): Fix netstack then remove the line below.
expect_netstack_failure = True,
),
PacketimpactTestInfo(
name = "ipv6_unknown_options_action",