diff --git a/pkg/tcpip/transport/tcp/BUILD b/pkg/tcpip/transport/tcp/BUILD index 2087d7efcd..74f7279719 100644 --- a/pkg/tcpip/transport/tcp/BUILD +++ b/pkg/tcpip/transport/tcp/BUILD @@ -162,6 +162,7 @@ go_library( "pending_processing_mutex.go", "protocol.go", "protocol_mutex.go", + "protocol_state.go", "rack.go", "rcv.go", "rcv_queue_mutex.go", diff --git a/pkg/tcpip/transport/tcp/protocol.go b/pkg/tcpip/transport/tcp/protocol.go index ec80705d19..7c911632b2 100644 --- a/pkg/tcpip/transport/tcp/protocol.go +++ b/pkg/tcpip/transport/tcp/protocol.go @@ -114,9 +114,11 @@ type protocol struct { // This is immutable after creation. probe TCPProbeFunc `state:"nosave"` - // The following secrets are initialized once and stay unchanged after. - seqnumSecret [16]byte - tsOffsetSecret [16]byte + // The following secrets are used for ISN and timestamp-offset + // generation. They are not serialized into checkpoint state and are + // freshly drawn from the secure RNG on restore (see afterLoad). + seqnumSecret [16]byte `state:"nosave"` + tsOffsetSecret [16]byte `state:"nosave"` } // Number returns the tcp protocol number. diff --git a/pkg/tcpip/transport/tcp/protocol_state.go b/pkg/tcpip/transport/tcp/protocol_state.go new file mode 100644 index 0000000000..2b3e761318 --- /dev/null +++ b/pkg/tcpip/transport/tcp/protocol_state.go @@ -0,0 +1,31 @@ +// Copyright 2026 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +import ( + "context" + "fmt" +) + +// afterLoad is invoked by stateify. +func (p *protocol) afterLoad(ctx context.Context) { + rng := p.stack.SecureRNG() + if n, err := rng.Reader.Read(p.seqnumSecret[:]); err != nil || n != len(p.seqnumSecret) { + panic(fmt.Sprintf("rng.Reader.Read(seqnumSecret) failed: n=%d err=%v", n, err)) + } + if n, err := rng.Reader.Read(p.tsOffsetSecret[:]); err != nil || n != len(p.tsOffsetSecret) { + panic(fmt.Sprintf("rng.Reader.Read(tsOffsetSecret) failed: n=%d err=%v", n, err)) + } +}