From 5d2bf2546805afa09a6f6d9b23ec267823e32205 Mon Sep 17 00:00:00 2001 From: Nayana Bidari Date: Fri, 10 Nov 2023 14:08:08 -0800 Subject: [PATCH] Change IPv6 fragment ID generation algorithm. This addresses an issue discovered by Inon Kaplan (PhD candidate in the Hebrew University School of Computer Science and Engineering), Ron Even (BSc graduate of Bar Ilan University) and Amit Klein (faculty member in the Hebrew University School of Computer Science and Engineering). Details will be provided in their paper, to be presented in a forthcoming academic conference. The fragement ID generation for IPv6 is changed to return a completely random uint32 number. PiperOrigin-RevId: 581364034 --- pkg/tcpip/network/ipv6/BUILD | 1 - pkg/tcpip/network/ipv6/ipv6.go | 48 +++++++--------------------------- 2 files changed, 9 insertions(+), 40 deletions(-) diff --git a/pkg/tcpip/network/ipv6/BUILD b/pkg/tcpip/network/ipv6/BUILD index 8b57d808c..60efd669e 100644 --- a/pkg/tcpip/network/ipv6/BUILD +++ b/pkg/tcpip/network/ipv6/BUILD @@ -23,7 +23,6 @@ go_library( "//pkg/tcpip", "//pkg/tcpip/header", "//pkg/tcpip/header/parse", - "//pkg/tcpip/network/hash", "//pkg/tcpip/network/internal/fragmentation", "//pkg/tcpip/network/internal/ip", "//pkg/tcpip/network/internal/multicast", diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go index 21eaec105..e8d02ea6b 100644 --- a/pkg/tcpip/network/ipv6/ipv6.go +++ b/pkg/tcpip/network/ipv6/ipv6.go @@ -16,9 +16,7 @@ package ipv6 import ( - "encoding/binary" "fmt" - "hash/fnv" "math" "reflect" "sort" @@ -30,7 +28,6 @@ import ( "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/header/parse" - "gvisor.dev/gvisor/pkg/tcpip/network/hash" "gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation" "gvisor.dev/gvisor/pkg/tcpip/network/internal/ip" "gvisor.dev/gvisor/pkg/tcpip/network/internal/multicast" @@ -777,7 +774,7 @@ func (e *endpoint) handleFragments(r *stack.Route, networkMTU uint32, pkt stack. pf := fragmentation.MakePacketFragmenter(pkt, fragmentPayloadLen, calculateFragmentReserve(pkt)) defer pf.Release() - id := e.protocol.ids[hashRoute(r, e.protocol.hashIV)%buckets].Add(1) + id := e.getFragmentID() var n int for { @@ -2288,9 +2285,6 @@ type protocol struct { multicastForwardingDisp stack.MulticastForwardingEventDispatcher } - ids []atomicbitops.Uint32 - hashIV uint32 - // defaultTTL is the current default TTL for the protocol. Only the // uint8 portion of it is meaningful. defaultTTL atomicbitops.Uint32 @@ -2749,21 +2743,10 @@ type Options struct { func NewProtocolWithOptions(opts Options) stack.NetworkProtocolFactory { opts.NDPConfigs.validate() - ids := hash.RandN32(buckets) - hashIV := hash.RandN32(1)[0] - - atomicIds := make([]atomicbitops.Uint32, len(ids)) - for i := range ids { - atomicIds[i] = atomicbitops.FromUint32(ids[i]) - } - return func(s *stack.Stack) stack.NetworkProtocol { p := &protocol{ stack: s, options: opts, - - ids: atomicIds, - hashIV: hashIV, } p.fragmentation = fragmentation.NewFragmentation(header.IPv6FragmentExtHdrFragmentOffsetBytesPerUnit, fragmentation.HighFragThreshold, fragmentation.LowFragThreshold, ReassembleTimeout, s.Clock(), p) p.mu.eps = make(map[tcpip.NICID]*endpoint) @@ -2800,28 +2783,15 @@ func calculateFragmentReserve(pkt stack.PacketBufferPtr) int { return pkt.AvailableHeaderBytes() + len(pkt.NetworkHeader().Slice()) + header.IPv6FragmentHeaderSize } -// hashRoute calculates a hash value for the given route. It uses the source & -// destination address and 32-bit number to generate the hash. -func hashRoute(r *stack.Route, hashIV uint32) uint32 { - // The FNV-1a was chosen because it is a fast hashing algorithm, and - // cryptographic properties are not needed here. - h := fnv.New32a() - localAddr := r.LocalAddress() - if _, err := h.Write(localAddr.AsSlice()); err != nil { - panic(fmt.Sprintf("Hash.Write: %s, but Hash' implementation of Write is not expected to ever return an error", err)) +// getFragmentID returns a random uint32 number (other than zero) to be used as +// fragment ID in the IPv6 header. +func (e *endpoint) getFragmentID() uint32 { + rng := e.protocol.stack.SecureRNG() + id := rng.Uint32() + for id == 0 { + id = rng.Uint32() } - remoteAddr := r.RemoteAddress() - if _, err := h.Write(remoteAddr.AsSlice()); err != nil { - panic(fmt.Sprintf("Hash.Write: %s, but Hash' implementation of Write is not expected to ever return an error", err)) - } - - s := make([]byte, 4) - binary.LittleEndian.PutUint32(s, hashIV) - if _, err := h.Write(s); err != nil { - panic(fmt.Sprintf("Hash.Write: %s, but Hash' implementation of Write is not expected ever to return an error", err)) - } - - return h.Sum32() + return id } func buildNextFragment(pf *fragmentation.PacketFragmenter, originalIPHeaders header.IPv6, transportProto tcpip.TransportProtocolNumber, id uint32) (stack.PacketBufferPtr, bool) {