mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Validate the checksum for incoming ICMPv6 packets
This change validates the ICMPv6 checksum field before further processing an ICMPv6 packet. Tests: Unittests to make sure that only ICMPv6 packets with a valid checksum are accepted/processed. Existing tests using checker.ICMPv6 now also check the ICMPv6 checksum field. PiperOrigin-RevId: 276779148
This commit is contained in:
committed by
gVisor bot
parent
8f029b3f82
commit
5a421058a0
@@ -10,6 +10,7 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/buffer",
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/tcpip/seqnum",
|
||||
],
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
|
||||
)
|
||||
@@ -639,6 +640,8 @@ func ICMPv4Code(want byte) TransportChecker {
|
||||
|
||||
// ICMPv6 creates a checker that checks that the transport protocol is ICMPv6 and
|
||||
// potentially additional ICMPv6 header fields.
|
||||
//
|
||||
// ICMPv6 will validate the checksum field before calling checkers.
|
||||
func ICMPv6(checkers ...TransportChecker) NetworkChecker {
|
||||
return func(t *testing.T, h []header.Network) {
|
||||
t.Helper()
|
||||
@@ -650,6 +653,10 @@ func ICMPv6(checkers ...TransportChecker) NetworkChecker {
|
||||
}
|
||||
|
||||
icmp := header.ICMPv6(last.Payload())
|
||||
if got, want := icmp.Checksum(), header.ICMPv6Checksum(icmp, last.SourceAddress(), last.DestinationAddress(), buffer.VectorisedView{}); got != want {
|
||||
t.Fatalf("Bad ICMPv6 checksum; got %d, want %d", got, want)
|
||||
}
|
||||
|
||||
for _, f := range checkers {
|
||||
f(t, icmp)
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ func (b ICMPv6) Checksum() uint16 {
|
||||
return binary.BigEndian.Uint16(b[icmpv6ChecksumOffset:])
|
||||
}
|
||||
|
||||
// SetChecksum calculates and sets the ICMP checksum field.
|
||||
// SetChecksum sets the ICMP checksum field.
|
||||
func (b ICMPv6) SetChecksum(checksum uint16) {
|
||||
binary.BigEndian.PutUint16(b[icmpv6ChecksumOffset:], checksum)
|
||||
}
|
||||
@@ -197,7 +197,7 @@ func (b ICMPv6) Payload() []byte {
|
||||
return b[ICMPv6PayloadOffset:]
|
||||
}
|
||||
|
||||
// ICMPv6Checksum calculates the ICMP checksum over the provided ICMP header,
|
||||
// ICMPv6Checksum calculates the ICMP checksum over the provided ICMPv6 header,
|
||||
// IPv6 src/dst addresses and the payload.
|
||||
func ICMPv6Checksum(h ICMPv6, src, dst tcpip.Address, vv buffer.VectorisedView) uint16 {
|
||||
// Calculate the IPv6 pseudo-header upper-layer checksum.
|
||||
|
||||
@@ -519,6 +519,7 @@ func TestIPv6ReceiveControl(t *testing.T) {
|
||||
newUint16 := func(v uint16) *uint16 { return &v }
|
||||
|
||||
const mtu = 0xffff
|
||||
const outerSrcAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa"
|
||||
cases := []struct {
|
||||
name string
|
||||
expectedCount int
|
||||
@@ -570,7 +571,7 @@ func TestIPv6ReceiveControl(t *testing.T) {
|
||||
PayloadLength: uint16(len(view) - header.IPv6MinimumSize - c.trunc),
|
||||
NextHeader: uint8(header.ICMPv6ProtocolNumber),
|
||||
HopLimit: 20,
|
||||
SrcAddr: "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa",
|
||||
SrcAddr: outerSrcAddr,
|
||||
DstAddr: localIpv6Addr,
|
||||
})
|
||||
|
||||
@@ -618,6 +619,10 @@ func TestIPv6ReceiveControl(t *testing.T) {
|
||||
o.extra = c.expectedExtra
|
||||
|
||||
vv := view[:len(view)-c.trunc].ToVectorisedView()
|
||||
|
||||
// Set ICMPv6 checksum.
|
||||
icmp.SetChecksum(header.ICMPv6Checksum(icmp, outerSrcAddr, localIpv6Addr, buffer.VectorisedView{}))
|
||||
|
||||
ep.HandlePacket(&r, vv)
|
||||
if want := c.expectedCount; o.controlCalls != want {
|
||||
t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, o.controlCalls, want)
|
||||
|
||||
@@ -72,6 +72,18 @@ func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, vv buffer.V
|
||||
h := header.ICMPv6(v)
|
||||
iph := header.IPv6(netHeader)
|
||||
|
||||
// Validate ICMPv6 checksum before processing the packet.
|
||||
//
|
||||
// Only the first view in vv is accounted for by h. To account for the
|
||||
// rest of vv, a shallow copy is made and the first view is removed.
|
||||
// This copy is used as extra payload during the checksum calculation.
|
||||
payload := vv
|
||||
payload.RemoveFirst()
|
||||
if got, want := h.Checksum(), header.ICMPv6Checksum(h, iph.SourceAddress(), iph.DestinationAddress(), payload); got != want {
|
||||
received.Invalid.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
// As per RFC 4861 sections 4.1 - 4.5, 6.1.1, 6.1.2, 7.1.1, 7.1.2 and
|
||||
// 8.1, nodes MUST silently drop NDP packets where the Hop Limit field
|
||||
// in the IPv6 header is not set to 255.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -445,13 +445,13 @@ func send6(r *stack.Route, ident uint16, data buffer.View, ttl uint8) *tcpip.Err
|
||||
return tcpip.ErrInvalidEndpointState
|
||||
}
|
||||
|
||||
icmpv6.SetChecksum(0)
|
||||
icmpv6.SetChecksum(^header.Checksum(icmpv6, header.Checksum(data, 0)))
|
||||
dataVV := data.ToVectorisedView()
|
||||
icmpv6.SetChecksum(header.ICMPv6Checksum(icmpv6, r.LocalAddress, r.RemoteAddress, dataVV))
|
||||
|
||||
if ttl == 0 {
|
||||
ttl = r.DefaultTTL()
|
||||
}
|
||||
return r.WritePacket(nil /* gso */, hdr, data.ToVectorisedView(), stack.NetworkHeaderParams{Protocol: header.ICMPv6ProtocolNumber, TTL: ttl, TOS: stack.DefaultTOS})
|
||||
return r.WritePacket(nil /* gso */, hdr, dataVV, stack.NetworkHeaderParams{Protocol: header.ICMPv6ProtocolNumber, TTL: ttl, TOS: stack.DefaultTOS})
|
||||
}
|
||||
|
||||
func (e *endpoint) checkV4Mapped(addr *tcpip.FullAddress, allowMismatch bool) (tcpip.NetworkProtocolNumber, *tcpip.Error) {
|
||||
|
||||
Reference in New Issue
Block a user