Use cryptographic hash functions for TCP

gVisor used to use jenkins for generating initial sequence number and timestamp
offset. Since it is not a cryptographic hash function and easily reversible, it
can cause security concerns. Replaced it with sha256 which is a secure hash
function.

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.

Fixes #6473

PiperOrigin-RevId: 584211221
This commit is contained in:
Zeling Feng
2023-11-20 21:46:05 -08:00
committed by gVisor bot
parent f221e212aa
commit f956b5ac17
2 changed files with 16 additions and 9 deletions
+8 -3
View File
@@ -15,6 +15,7 @@
package tcp
import (
"crypto/sha256"
"encoding/binary"
"fmt"
"math"
@@ -23,7 +24,6 @@ import (
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/checksum"
"gvisor.dev/gvisor/pkg/tcpip/hash/jenkins"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
"gvisor.dev/gvisor/pkg/tcpip/stack"
@@ -236,10 +236,14 @@ func (h *handshake) resetState() {
// generateSecureISN generates a secure Initial Sequence number based on the
// recommendation here https://tools.ietf.org/html/rfc6528#page-3.
func generateSecureISN(id stack.TransportEndpointID, clock tcpip.Clock, seed uint32) seqnum.Value {
isnHasher := jenkins.Sum32(seed)
isnHasher := sha256.New()
seedBuf := make([]byte, 4)
binary.LittleEndian.PutUint32(seedBuf, seed)
// Per hash.Hash.Writer:
//
// It never returns an error.
_, _ = isnHasher.Write(seedBuf)
_, _ = isnHasher.Write(id.LocalAddress.AsSlice())
_, _ = isnHasher.Write(id.RemoteAddress.AsSlice())
portBuf := make([]byte, 2)
@@ -257,7 +261,8 @@ func generateSecureISN(id stack.TransportEndpointID, clock tcpip.Clock, seed uin
//
// Which sort of guarantees that we won't reuse the ISN for a new
// connection for the same tuple for at least 274s.
isn := isnHasher.Sum32() + uint32(clock.NowMonotonic().Sub(tcpip.MonotonicTime{}).Nanoseconds()>>6)
hash := binary.LittleEndian.Uint32(isnHasher.Sum(nil)[:4])
isn := hash + uint32(clock.NowMonotonic().Sub(tcpip.MonotonicTime{}).Nanoseconds()>>6)
return seqnum.Value(isn)
}
+8 -6
View File
@@ -16,13 +16,14 @@
package tcp
import (
"crypto/sha256"
"encoding/binary"
"runtime"
"strings"
"time"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/hash/jenkins"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/header/parse"
"gvisor.dev/gvisor/pkg/tcpip/internal/tcp"
@@ -178,16 +179,17 @@ func (p *protocol) tsOffset(src, dst tcpip.Address) tcp.TSOffset {
//
// See https://tools.ietf.org/html/rfc7323#section-5.4 for details on
// why this is required.
//
// TODO(https://gvisor.dev/issues/6473): This is not really secure as
// it does not use the recommended algorithm linked above.
h := jenkins.Sum32(p.tsOffsetSecret)
h := sha256.New()
secretBuf := make([]byte, 4)
binary.LittleEndian.PutUint32(secretBuf, p.tsOffsetSecret)
// Per hash.Hash.Writer:
//
// It never returns an error.
_, _ = h.Write(secretBuf)
_, _ = h.Write(src.AsSlice())
_, _ = h.Write(dst.AsSlice())
return tcp.NewTSOffset(h.Sum32())
return tcp.NewTSOffset(binary.LittleEndian.Uint32(h.Sum(nil)[:4]))
}
// replyWithReset replies to the given segment with a reset segment.