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
This commit is contained in:
Nayana Bidari
2023-11-10 14:10:42 -08:00
committed by gVisor bot
parent cbdb2c61b1
commit 5d2bf25468
2 changed files with 9 additions and 40 deletions
-1
View File
@@ -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",
+9 -39
View File
@@ -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) {