snapshot: sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1

Содержимое пина, зафиксированного в go.mod sing-box-lx, одним коммитом
без истории. Полная история SagerNet/gvisor — 1.45 ГБ и клонируется в
каждой CI-джобе; наша дельта — одна вставка в одну функцию, история для
неё не нужна.

Module path github.com/sagernet/gvisor сохранён намеренно: на него
опирается replace-директива суперпроекта.

Патч поверх — отдельным коммитом, чтобы дельта читалась одним git show
и переносилась на новый пин копированием.

SPECS/TASKS/048-GVISOR_HANDSHAKE_NIL_CRASH
This commit is contained in:
Leadaxe 2026-08-04 15:50:08 +03:00
commit 2c4ae3b0a4
712 changed files with 185689 additions and 0 deletions

View file

@ -0,0 +1,623 @@
// Copyright 2019 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 packet provides the implementation of packet sockets (see
// packet(7)). Packet sockets allow applications to:
//
// - manually write and inspect link, network, and transport headers
// - receive all traffic of a given network protocol, or all protocols
//
// Packet sockets are similar to raw sockets, but provide even more power to
// users, letting them effectively talk directly to the network device.
//
// Packet sockets skip the input and output iptables chains.
package packet
import (
"io"
"math"
"time"
"github.com/sagernet/gvisor/pkg/buffer"
"github.com/sagernet/gvisor/pkg/tcpip"
"github.com/sagernet/gvisor/pkg/tcpip/header"
"github.com/sagernet/gvisor/pkg/tcpip/stack"
"github.com/sagernet/gvisor/pkg/waiter"
)
type tpacketVersion int
const (
tpacketVersion1 tpacketVersion = iota
tpacketVersion2
)
var _ stack.MappablePacketEndpoint = (*endpoint)(nil)
// +stateify savable
type packet struct {
packetEntry
// data holds the actual packet data, including any headers and payload.
data *stack.PacketBuffer
receivedAt time.Time `state:".(int64)"`
// senderAddr is the network address of the sender.
senderAddr tcpip.FullAddress
// packetInfo holds additional information like the protocol
// of the packet etc.
packetInfo tcpip.LinkPacketInfo
}
// endpoint is the packet socket implementation of tcpip.Endpoint. It is legal
// to have goroutines make concurrent calls into the endpoint.
//
// Lock order:
//
// endpoint.mu
// endpoint.rcvMu
// endpoint.packetMmapMu
//
// +stateify savable
type endpoint struct {
tcpip.DefaultSocketOptionsHandler
// The following fields are initialized at creation time and are
// immutable.
stack *stack.Stack
waiterQueue *waiter.Queue
cooked bool
ops tcpip.SocketOptions
stats tcpip.TransportEndpointStats
// The following fields are used to manage the receive queue.
rcvMu rcvMutex `state:"nosave"`
// +checklocks:rcvMu
rcvList packetList
// +checklocks:rcvMu
rcvBufSize int
// +checklocks:rcvMu
rcvClosed bool
// +checklocks:rcvMu
rcvDisabled bool
mu endpointRWMutex `state:"nosave"`
// +checklocks:mu
closed bool
// +checklocks:mu
boundNetProto tcpip.NetworkProtocolNumber
// +checklocks:mu
boundNIC tcpip.NICID
lastErrorMu lastErrorMutex `state:"nosave"`
// +checklocks:lastErrorMu
lastError tcpip.Error
packetMmapMu packetMmapRWMutex `state:"nosave"`
// +checklocks:packetMmapMu
packetMMapVersion tpacketVersion
// +checklocks:packetMmapMu
packetMMapReserve int
// +checklocks:packetMmapMu
packetMMapEp stack.PacketMMapEndpoint
}
// NewEndpoint returns a new packet endpoint.
func NewEndpoint(s *stack.Stack, cooked bool, netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) tcpip.Endpoint {
ep := &endpoint{
stack: s,
cooked: cooked,
boundNetProto: netProto,
waiterQueue: waiterQueue,
}
ep.ops.InitHandler(ep, ep.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits)
ep.ops.SetReceiveBufferSize(32*1024, false /* notify */)
// Override with stack defaults.
var ss tcpip.SendBufferSizeOption
if err := s.Option(&ss); err == nil {
ep.ops.SetSendBufferSize(int64(ss.Default), false /* notify */)
}
var rs tcpip.ReceiveBufferSizeOption
if err := s.Option(&rs); err == nil {
ep.ops.SetReceiveBufferSize(int64(rs.Default), false /* notify */)
}
s.RegisterPacketEndpoint(0, netProto, ep)
return ep
}
// Abort implements stack.TransportEndpoint.Abort.
func (ep *endpoint) Abort() {
ep.Close()
}
// Close implements tcpip.Endpoint.Close.
func (ep *endpoint) Close() {
ep.mu.Lock()
defer ep.mu.Unlock()
if ep.closed {
return
}
ep.stack.UnregisterPacketEndpoint(ep.boundNIC, ep.boundNetProto, ep)
ep.packetMmapMu.Lock()
if ep.packetMMapEp != nil {
ep.packetMMapEp.Close()
ep.packetMMapEp = nil
}
ep.packetMmapMu.Unlock()
ep.rcvMu.Lock()
defer ep.rcvMu.Unlock()
// Clear the receive list.
ep.rcvClosed = true
ep.rcvBufSize = 0
for !ep.rcvList.Empty() {
p := ep.rcvList.Front()
ep.rcvList.Remove(p)
p.data.DecRef()
}
ep.closed = true
ep.waiterQueue.Notify(waiter.EventHUp | waiter.EventErr | waiter.ReadableEvents | waiter.WritableEvents)
}
// ModerateRecvBuf implements tcpip.Endpoint.ModerateRecvBuf.
func (*endpoint) ModerateRecvBuf(int) {}
// Read implements tcpip.Endpoint.Read.
func (ep *endpoint) Read(dst io.Writer, opts tcpip.ReadOptions) (tcpip.ReadResult, tcpip.Error) {
ep.rcvMu.Lock()
// If there's no data to read, return that read would block or that the
// endpoint is closed.
if ep.rcvList.Empty() {
var err tcpip.Error = &tcpip.ErrWouldBlock{}
if ep.rcvClosed {
ep.stats.ReadErrors.ReadClosed.Increment()
err = &tcpip.ErrClosedForReceive{}
}
ep.rcvMu.Unlock()
return tcpip.ReadResult{}, err
}
packet := ep.rcvList.Front()
if !opts.Peek {
ep.rcvList.Remove(packet)
defer packet.data.DecRef()
ep.rcvBufSize -= packet.data.Size()
}
ep.rcvMu.Unlock()
res := tcpip.ReadResult{
Total: packet.data.Size(),
ControlMessages: tcpip.ReceivableControlMessages{
HasTimestamp: true,
Timestamp: packet.receivedAt,
},
}
if opts.NeedRemoteAddr {
res.RemoteAddr = packet.senderAddr
}
if opts.NeedLinkPacketInfo {
res.LinkPacketInfo = packet.packetInfo
}
n, err := packet.data.Data().ReadTo(dst, opts.Peek)
if n == 0 && err != nil {
return res, &tcpip.ErrBadBuffer{}
}
res.Count = n
return res, nil
}
func (ep *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcpip.Error) {
if !ep.stack.PacketEndpointWriteSupported() {
return 0, &tcpip.ErrNotSupported{}
}
ep.mu.Lock()
closed := ep.closed
nicID := ep.boundNIC
proto := ep.boundNetProto
ep.mu.Unlock()
if closed {
return 0, &tcpip.ErrClosedForSend{}
}
var remote tcpip.LinkAddress
if to := opts.To; to != nil {
remote = to.LinkAddr
if n := to.NIC; n != 0 {
nicID = n
}
if p := to.Port; p != 0 {
proto = tcpip.NetworkProtocolNumber(p)
}
}
if nicID == 0 {
return 0, &tcpip.ErrInvalidOptionValue{}
}
// Prevents giant buffer allocations.
if p.Len() > header.DatagramMaximumSize {
return 0, &tcpip.ErrMessageTooLong{}
}
var payload buffer.Buffer
if _, err := payload.WriteFromReader(p, int64(p.Len())); err != nil {
return 0, &tcpip.ErrBadBuffer{}
}
payloadSz := payload.Size()
if err := func() tcpip.Error {
if ep.cooked {
return ep.stack.WritePacketToRemote(nicID, remote, proto, payload)
}
return ep.stack.WriteRawPacket(nicID, proto, payload)
}(); err != nil {
return 0, err
}
return payloadSz, nil
}
// Disconnect implements tcpip.Endpoint.Disconnect. Packet sockets cannot be
// disconnected, and this function always returns tpcip.ErrNotSupported.
func (*endpoint) Disconnect() tcpip.Error {
return &tcpip.ErrNotSupported{}
}
// Connect implements tcpip.Endpoint.Connect. Packet sockets cannot be
// connected, and this function always returns *tcpip.ErrNotSupported.
func (*endpoint) Connect(tcpip.FullAddress) tcpip.Error {
return &tcpip.ErrNotSupported{}
}
// Shutdown implements tcpip.Endpoint.Shutdown. Packet sockets cannot be used
// with Shutdown, and this function always returns *tcpip.ErrNotSupported.
func (*endpoint) Shutdown(tcpip.ShutdownFlags) tcpip.Error {
return &tcpip.ErrNotSupported{}
}
// Listen implements tcpip.Endpoint.Listen. Packet sockets cannot be used with
// Listen, and this function always returns *tcpip.ErrNotSupported.
func (*endpoint) Listen(int) tcpip.Error {
return &tcpip.ErrNotSupported{}
}
// Accept implements tcpip.Endpoint.Accept. Packet sockets cannot be used with
// Accept, and this function always returns *tcpip.ErrNotSupported.
func (*endpoint) Accept(*tcpip.FullAddress) (tcpip.Endpoint, *waiter.Queue, tcpip.Error) {
return nil, nil, &tcpip.ErrNotSupported{}
}
// Bind implements tcpip.Endpoint.Bind.
func (ep *endpoint) Bind(addr tcpip.FullAddress) tcpip.Error {
// "By default, all packets of the specified protocol type are passed
// to a packet socket. To get packets only from a specific interface
// use bind(2) specifying an address in a struct sockaddr_ll to bind
// the packet socket to an interface. Fields used for binding are
// sll_family (should be AF_PACKET), sll_protocol, and sll_ifindex."
// - packet(7).
ep.mu.Lock()
defer ep.mu.Unlock()
netProto := tcpip.NetworkProtocolNumber(addr.Port)
if netProto == 0 {
// Do not allow unbinding the network protocol.
netProto = ep.boundNetProto
}
if ep.boundNIC == addr.NIC && ep.boundNetProto == netProto {
// Already bound to the requested NIC and network protocol.
return nil
}
// TODO(https://gvisor.dev/issue/6618): Unregister after registering the new
// binding.
ep.stack.UnregisterPacketEndpoint(ep.boundNIC, ep.boundNetProto, ep)
ep.boundNIC = 0
ep.boundNetProto = 0
// Bind endpoint to receive packets from specific interface.
if err := ep.stack.RegisterPacketEndpoint(addr.NIC, netProto, ep); err != nil {
return err
}
ep.boundNIC = addr.NIC
ep.boundNetProto = netProto
return nil
}
// GetLocalAddress implements tcpip.Endpoint.GetLocalAddress.
func (ep *endpoint) GetLocalAddress() (tcpip.FullAddress, tcpip.Error) {
ep.mu.RLock()
defer ep.mu.RUnlock()
return tcpip.FullAddress{
NIC: ep.boundNIC,
Port: uint16(ep.boundNetProto),
}, nil
}
// GetRemoteAddress implements tcpip.Endpoint.GetRemoteAddress.
func (*endpoint) GetRemoteAddress() (tcpip.FullAddress, tcpip.Error) {
// Even a connected socket doesn't return a remote address.
return tcpip.FullAddress{}, &tcpip.ErrNotConnected{}
}
// Readiness implements tcpip.Endpoint.Readiness.
func (ep *endpoint) Readiness(mask waiter.EventMask) waiter.EventMask {
// The endpoint is always writable.
result := waiter.WritableEvents & mask
// Determine whether the endpoint is readable.
if (mask & waiter.ReadableEvents) != 0 {
ep.packetMmapMu.RLock()
if ep.packetMMapEp != nil {
result |= ep.packetMMapEp.Readiness(mask)
}
ep.packetMmapMu.RUnlock()
ep.rcvMu.Lock()
if !ep.rcvList.Empty() || ep.rcvClosed {
result |= waiter.ReadableEvents
}
ep.rcvMu.Unlock()
}
return result
}
// SetSockOpt implements tcpip.Endpoint.SetSockOpt.
func (ep *endpoint) SetSockOpt(opt tcpip.SettableSocketOption) tcpip.Error {
switch opt.(type) {
case *tcpip.SocketDetachFilterOption:
return nil
case *tcpip.TpacketReq:
ep.rcvMu.Lock()
defer ep.rcvMu.Unlock()
if !ep.rcvList.Empty() {
return &tcpip.ErrWouldBlock{}
}
return nil
default:
return &tcpip.ErrUnknownProtocolOption{}
}
}
// SetSockOptInt implements tcpip.Endpoint.SetSockOptInt.
func (ep *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) tcpip.Error {
switch opt {
case tcpip.PacketMMapVersionOption:
ep.packetMmapMu.Lock()
defer ep.packetMmapMu.Unlock()
// We support up to TPACKET_V2.
version := tpacketVersion(v)
switch version {
case tpacketVersion1, tpacketVersion2:
if ep.packetMMapEp != nil {
return &tcpip.ErrEndpointBusy{}
}
ep.packetMMapVersion = version
return nil
default:
return &tcpip.ErrInvalidOptionValue{}
}
case tcpip.PacketMMapReserveOption:
ep.packetMmapMu.Lock()
defer ep.packetMmapMu.Unlock()
if ep.packetMMapEp != nil {
return &tcpip.ErrEndpointBusy{}
}
if uint32(v) > uint32(math.MaxInt32) {
return &tcpip.ErrInvalidOptionValue{}
}
ep.packetMMapReserve = v
return nil
default:
return &tcpip.ErrUnknownProtocolOption{}
}
}
func (ep *endpoint) LastError() tcpip.Error {
ep.lastErrorMu.Lock()
defer ep.lastErrorMu.Unlock()
err := ep.lastError
ep.lastError = nil
return err
}
// UpdateLastError implements tcpip.SocketOptionsHandler.UpdateLastError.
func (ep *endpoint) UpdateLastError(err tcpip.Error) {
ep.lastErrorMu.Lock()
ep.lastError = err
ep.lastErrorMu.Unlock()
}
// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
func (ep *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) tcpip.Error {
switch opt.(type) {
case *tcpip.TpacketStats:
ep.packetMmapMu.RLock()
defer ep.packetMmapMu.RUnlock()
if ep.packetMMapEp == nil {
return nil
}
*(opt.(*tcpip.TpacketStats)) = ep.packetMMapEp.Stats()
return nil
default:
return &tcpip.ErrUnknownProtocolOption{}
}
}
// GetSockOptInt implements tcpip.Endpoint.GetSockOptInt.
func (ep *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, tcpip.Error) {
switch opt {
case tcpip.ReceiveQueueSizeOption:
v := 0
ep.rcvMu.Lock()
if !ep.rcvList.Empty() {
p := ep.rcvList.Front()
v = p.data.Size()
}
ep.rcvMu.Unlock()
return v, nil
default:
return -1, &tcpip.ErrUnknownProtocolOption{}
}
}
// handlePacket implements stack.PacketEndpoint.HandlePacket
func (ep *endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
ep.packetMmapMu.RLock()
if ep.packetMMapEp != nil {
if handled := ep.packetMMapEp.HandlePacket(nicID, netProto, pkt); handled {
ep.packetMmapMu.RUnlock()
return
}
}
ep.packetMmapMu.RUnlock()
wasEmpty := ep.handlePacketInner(nicID, netProto, pkt)
ep.stats.PacketsReceived.Increment()
// Notify waiters that there's data to be read.
if wasEmpty {
ep.waiterQueue.Notify(waiter.ReadableEvents)
}
}
func (ep *endpoint) HandlePacketMMapCopy(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
_ = ep.handlePacketInner(nicID, netProto, pkt)
}
func (ep *endpoint) handlePacketInner(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) bool {
ep.rcvMu.Lock()
// Drop the packet if our buffer is currently full.
if ep.rcvClosed {
ep.rcvMu.Unlock()
ep.stack.Stats().DroppedPackets.Increment()
ep.stats.ReceiveErrors.ClosedReceiver.Increment()
return false
}
rcvBufSize := ep.ops.GetReceiveBufferSize()
if ep.rcvDisabled || ep.rcvBufSize >= int(rcvBufSize) {
ep.rcvMu.Unlock()
ep.stack.Stats().DroppedPackets.Increment()
ep.stats.ReceiveErrors.ReceiveBufferOverflow.Increment()
return false
}
wasEmpty := ep.rcvBufSize == 0
rcvdPkt := packet{
packetInfo: tcpip.LinkPacketInfo{
Protocol: netProto,
PktType: pkt.PktType,
},
senderAddr: tcpip.FullAddress{
NIC: nicID,
},
receivedAt: ep.stack.Clock().Now(),
}
if len(pkt.LinkHeader().Slice()) != 0 {
hdr := header.Ethernet(pkt.LinkHeader().Slice())
rcvdPkt.senderAddr.LinkAddr = hdr.SourceAddress()
}
// Raw packet endpoints include link-headers in received packets.
pktBuf := pkt.ToBuffer()
if ep.cooked {
// Cooked packet endpoints don't include the link-headers in received
// packets.
pktBuf.TrimFront(int64(len(pkt.LinkHeader().Slice()) + len(pkt.VirtioNetHeader().Slice())))
}
rcvdPkt.data = stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: pktBuf})
ep.rcvList.PushBack(&rcvdPkt)
ep.rcvBufSize += rcvdPkt.data.Size()
ep.rcvMu.Unlock()
return wasEmpty
}
// State implements socket.Socket.State.
func (*endpoint) State() uint32 {
return 0
}
// Info returns a copy of the endpoint info.
func (ep *endpoint) Info() tcpip.EndpointInfo {
ep.mu.RLock()
defer ep.mu.RUnlock()
return &stack.TransportEndpointInfo{NetProto: ep.boundNetProto}
}
// Stats returns a pointer to the endpoint stats.
func (ep *endpoint) Stats() tcpip.EndpointStats {
return &ep.stats
}
// SetOwner implements tcpip.Endpoint.SetOwner.
func (*endpoint) SetOwner(tcpip.PacketOwner) {}
// SocketOptions implements tcpip.Endpoint.SocketOptions.
func (ep *endpoint) SocketOptions() *tcpip.SocketOptions {
return &ep.ops
}
// GetPacketMMapOpts implements stack.MappablePacketEndpoint.GetPacketMMapOpts.
func (ep *endpoint) GetPacketMMapOpts(req *tcpip.TpacketReq, isRx bool) stack.PacketMMapOpts {
ep.packetMmapMu.Lock()
defer ep.packetMmapMu.Unlock()
return stack.PacketMMapOpts{
Req: req,
IsRx: isRx,
Cooked: ep.cooked,
Stack: ep.stack,
Wq: ep.waiterQueue,
PacketEndpoint: ep,
Version: int(ep.packetMMapVersion),
Reserve: uint32(ep.packetMMapReserve),
}
}
// SetPacketMMapEndpoint implements
// stack.MappablePacketEndpoint.SetPacketMMapEndpoint.
func (ep *endpoint) SetPacketMMapEndpoint(m stack.PacketMMapEndpoint) {
ep.packetMmapMu.Lock()
defer ep.packetMmapMu.Unlock()
ep.packetMMapEp = m
}
// GetPacketMMapEndpoint implements
// stack.MappablePacketEndpoint.GetPacketMMapEndpoint.
func (ep *endpoint) GetPacketMMapEndpoint() stack.PacketMMapEndpoint {
ep.packetMmapMu.RLock()
defer ep.packetMmapMu.RUnlock()
return ep.packetMMapEp
}

View file

@ -0,0 +1,96 @@
package packet
import (
"reflect"
"github.com/sagernet/gvisor/pkg/sync"
"github.com/sagernet/gvisor/pkg/sync/locking"
)
// RWMutex is sync.RWMutex with the correctness validator.
type endpointRWMutex struct {
mu sync.RWMutex
}
// lockNames is a list of user-friendly lock names.
// Populated in init.
var endpointlockNames []string
// lockNameIndex is used as an index passed to NestedLock and NestedUnlock,
// referring to an index within lockNames.
// Values are specified using the "consts" field of go_template_instance.
type endpointlockNameIndex int
// DO NOT REMOVE: The following function automatically replaced with lock index constants.
// LOCK_NAME_INDEX_CONSTANTS
const ()
// Lock locks m.
// +checklocksignore
func (m *endpointRWMutex) Lock() {
locking.AddGLock(endpointprefixIndex, -1)
m.mu.Lock()
}
// NestedLock locks m knowing that another lock of the same type is held.
// +checklocksignore
func (m *endpointRWMutex) NestedLock(i endpointlockNameIndex) {
locking.AddGLock(endpointprefixIndex, int(i))
m.mu.Lock()
}
// Unlock unlocks m.
// +checklocksignore
func (m *endpointRWMutex) Unlock() {
m.mu.Unlock()
locking.DelGLock(endpointprefixIndex, -1)
}
// NestedUnlock unlocks m knowing that another lock of the same type is held.
// +checklocksignore
func (m *endpointRWMutex) NestedUnlock(i endpointlockNameIndex) {
m.mu.Unlock()
locking.DelGLock(endpointprefixIndex, int(i))
}
// RLock locks m for reading.
// +checklocksignore
func (m *endpointRWMutex) RLock() {
locking.AddGLock(endpointprefixIndex, -1)
m.mu.RLock()
}
// RUnlock undoes a single RLock call.
// +checklocksignore
func (m *endpointRWMutex) RUnlock() {
m.mu.RUnlock()
locking.DelGLock(endpointprefixIndex, -1)
}
// RLockBypass locks m for reading without executing the validator.
// +checklocksignore
func (m *endpointRWMutex) RLockBypass() {
m.mu.RLock()
}
// RUnlockBypass undoes a single RLockBypass call.
// +checklocksignore
func (m *endpointRWMutex) RUnlockBypass() {
m.mu.RUnlock()
}
// DowngradeLock atomically unlocks rw for writing and locks it for reading.
// +checklocksignore
func (m *endpointRWMutex) DowngradeLock() {
m.mu.DowngradeLock()
}
var endpointprefixIndex *locking.MutexClass
// DO NOT REMOVE: The following function is automatically replaced.
func endpointinitLockNames() {}
func init() {
endpointinitLockNames()
endpointprefixIndex = locking.NewMutexClass(reflect.TypeOf(endpointRWMutex{}), endpointlockNames)
}

View file

@ -0,0 +1,64 @@
package packet
import (
"reflect"
"github.com/sagernet/gvisor/pkg/sync"
"github.com/sagernet/gvisor/pkg/sync/locking"
)
// Mutex is sync.Mutex with the correctness validator.
type rcvMutex struct {
mu sync.Mutex
}
var rcvprefixIndex *locking.MutexClass
// lockNames is a list of user-friendly lock names.
// Populated in init.
var rcvlockNames []string
// lockNameIndex is used as an index passed to NestedLock and NestedUnlock,
// referring to an index within lockNames.
// Values are specified using the "consts" field of go_template_instance.
type rcvlockNameIndex int
// DO NOT REMOVE: The following function automatically replaced with lock index constants.
// LOCK_NAME_INDEX_CONSTANTS
const ()
// Lock locks m.
// +checklocksignore
func (m *rcvMutex) Lock() {
locking.AddGLock(rcvprefixIndex, -1)
m.mu.Lock()
}
// NestedLock locks m knowing that another lock of the same type is held.
// +checklocksignore
func (m *rcvMutex) NestedLock(i rcvlockNameIndex) {
locking.AddGLock(rcvprefixIndex, int(i))
m.mu.Lock()
}
// Unlock unlocks m.
// +checklocksignore
func (m *rcvMutex) Unlock() {
locking.DelGLock(rcvprefixIndex, -1)
m.mu.Unlock()
}
// NestedUnlock unlocks m knowing that another lock of the same type is held.
// +checklocksignore
func (m *rcvMutex) NestedUnlock(i rcvlockNameIndex) {
locking.DelGLock(rcvprefixIndex, int(i))
m.mu.Unlock()
}
// DO NOT REMOVE: The following function is automatically replaced.
func rcvinitLockNames() {}
func init() {
rcvinitLockNames()
rcvprefixIndex = locking.NewMutexClass(reflect.TypeOf(rcvMutex{}), rcvlockNames)
}

View file

@ -0,0 +1,74 @@
// Copyright 2018 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 packet
import (
"context"
"fmt"
"time"
"github.com/sagernet/gvisor/pkg/tcpip"
"github.com/sagernet/gvisor/pkg/tcpip/stack"
)
// saveReceivedAt is invoked by stateify.
func (p *packet) saveReceivedAt() int64 {
return p.receivedAt.UnixNano()
}
// loadReceivedAt is invoked by stateify.
func (p *packet) loadReceivedAt(_ context.Context, nsec int64) {
p.receivedAt = time.Unix(0, nsec)
}
// beforeSave is invoked by stateify.
func (ep *endpoint) beforeSave() {
ep.rcvMu.Lock()
ep.rcvDisabled = true
ep.rcvMu.Unlock()
ep.stack.RegisterResumableEndpoint(ep)
}
// afterLoad is invoked by stateify.
func (ep *endpoint) afterLoad(ctx context.Context) {
if !ep.stack.IsSaveRestoreEnabled() {
ep.mu.Lock()
ep.stack = stack.RestoreStackFromContext(ctx)
ep.mu.Unlock()
}
ep.stack.RegisterRestoredEndpoint(ep)
}
// Restore implements tcpip.RestoredEndpoint.Restore.
func (ep *endpoint) Restore(_ *stack.Stack) {
ep.mu.Lock()
defer ep.mu.Unlock()
ep.ops.InitHandler(ep, ep.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits)
if err := ep.stack.RegisterPacketEndpoint(ep.boundNIC, ep.boundNetProto, ep); err != nil {
panic(fmt.Sprintf("RegisterPacketEndpoint(%d, %d, _): %s", ep.boundNIC, ep.boundNetProto, err))
}
ep.rcvMu.Lock()
ep.rcvDisabled = false
ep.rcvMu.Unlock()
}
// Resume implements tcpip.ResumableEndpoint.Resume.
func (ep *endpoint) Resume() {
ep.rcvMu.Lock()
defer ep.rcvMu.Unlock()
ep.rcvDisabled = false
}

View file

@ -0,0 +1,64 @@
package packet
import (
"reflect"
"github.com/sagernet/gvisor/pkg/sync"
"github.com/sagernet/gvisor/pkg/sync/locking"
)
// Mutex is sync.Mutex with the correctness validator.
type lastErrorMutex struct {
mu sync.Mutex
}
var lastErrorprefixIndex *locking.MutexClass
// lockNames is a list of user-friendly lock names.
// Populated in init.
var lastErrorlockNames []string
// lockNameIndex is used as an index passed to NestedLock and NestedUnlock,
// referring to an index within lockNames.
// Values are specified using the "consts" field of go_template_instance.
type lastErrorlockNameIndex int
// DO NOT REMOVE: The following function automatically replaced with lock index constants.
// LOCK_NAME_INDEX_CONSTANTS
const ()
// Lock locks m.
// +checklocksignore
func (m *lastErrorMutex) Lock() {
locking.AddGLock(lastErrorprefixIndex, -1)
m.mu.Lock()
}
// NestedLock locks m knowing that another lock of the same type is held.
// +checklocksignore
func (m *lastErrorMutex) NestedLock(i lastErrorlockNameIndex) {
locking.AddGLock(lastErrorprefixIndex, int(i))
m.mu.Lock()
}
// Unlock unlocks m.
// +checklocksignore
func (m *lastErrorMutex) Unlock() {
locking.DelGLock(lastErrorprefixIndex, -1)
m.mu.Unlock()
}
// NestedUnlock unlocks m knowing that another lock of the same type is held.
// +checklocksignore
func (m *lastErrorMutex) NestedUnlock(i lastErrorlockNameIndex) {
locking.DelGLock(lastErrorprefixIndex, int(i))
m.mu.Unlock()
}
// DO NOT REMOVE: The following function is automatically replaced.
func lastErrorinitLockNames() {}
func init() {
lastErrorinitLockNames()
lastErrorprefixIndex = locking.NewMutexClass(reflect.TypeOf(lastErrorMutex{}), lastErrorlockNames)
}

View file

@ -0,0 +1,239 @@
package packet
// ElementMapper provides an identity mapping by default.
//
// This can be replaced to provide a struct that maps elements to linker
// objects, if they are not the same. An ElementMapper is not typically
// required if: Linker is left as is, Element is left as is, or Linker and
// Element are the same type.
type packetElementMapper struct{}
// linkerFor maps an Element to a Linker.
//
// This default implementation should be inlined.
//
//go:nosplit
func (packetElementMapper) linkerFor(elem *packet) *packet { return elem }
// List is an intrusive list. Entries can be added to or removed from the list
// in O(1) time and with no additional memory allocations.
//
// The zero value for List is an empty list ready to use.
//
// To iterate over a list (where l is a List):
//
// for e := l.Front(); e != nil; e = e.Next() {
// // do something with e.
// }
//
// +stateify savable
type packetList struct {
head *packet
tail *packet
}
// Reset resets list l to the empty state.
func (l *packetList) Reset() {
l.head = nil
l.tail = nil
}
// Empty returns true iff the list is empty.
//
//go:nosplit
func (l *packetList) Empty() bool {
return l.head == nil
}
// Front returns the first element of list l or nil.
//
//go:nosplit
func (l *packetList) Front() *packet {
return l.head
}
// Back returns the last element of list l or nil.
//
//go:nosplit
func (l *packetList) Back() *packet {
return l.tail
}
// Len returns the number of elements in the list.
//
// NOTE: This is an O(n) operation.
//
//go:nosplit
func (l *packetList) Len() (count int) {
for e := l.Front(); e != nil; e = (packetElementMapper{}.linkerFor(e)).Next() {
count++
}
return count
}
// PushFront inserts the element e at the front of list l.
//
//go:nosplit
func (l *packetList) PushFront(e *packet) {
linker := packetElementMapper{}.linkerFor(e)
linker.SetNext(l.head)
linker.SetPrev(nil)
if l.head != nil {
packetElementMapper{}.linkerFor(l.head).SetPrev(e)
} else {
l.tail = e
}
l.head = e
}
// PushFrontList inserts list m at the start of list l, emptying m.
//
//go:nosplit
func (l *packetList) PushFrontList(m *packetList) {
if l.head == nil {
l.head = m.head
l.tail = m.tail
} else if m.head != nil {
packetElementMapper{}.linkerFor(l.head).SetPrev(m.tail)
packetElementMapper{}.linkerFor(m.tail).SetNext(l.head)
l.head = m.head
}
m.head = nil
m.tail = nil
}
// PushBack inserts the element e at the back of list l.
//
//go:nosplit
func (l *packetList) PushBack(e *packet) {
linker := packetElementMapper{}.linkerFor(e)
linker.SetNext(nil)
linker.SetPrev(l.tail)
if l.tail != nil {
packetElementMapper{}.linkerFor(l.tail).SetNext(e)
} else {
l.head = e
}
l.tail = e
}
// PushBackList inserts list m at the end of list l, emptying m.
//
//go:nosplit
func (l *packetList) PushBackList(m *packetList) {
if l.head == nil {
l.head = m.head
l.tail = m.tail
} else if m.head != nil {
packetElementMapper{}.linkerFor(l.tail).SetNext(m.head)
packetElementMapper{}.linkerFor(m.head).SetPrev(l.tail)
l.tail = m.tail
}
m.head = nil
m.tail = nil
}
// InsertAfter inserts e after b.
//
//go:nosplit
func (l *packetList) InsertAfter(b, e *packet) {
bLinker := packetElementMapper{}.linkerFor(b)
eLinker := packetElementMapper{}.linkerFor(e)
a := bLinker.Next()
eLinker.SetNext(a)
eLinker.SetPrev(b)
bLinker.SetNext(e)
if a != nil {
packetElementMapper{}.linkerFor(a).SetPrev(e)
} else {
l.tail = e
}
}
// InsertBefore inserts e before a.
//
//go:nosplit
func (l *packetList) InsertBefore(a, e *packet) {
aLinker := packetElementMapper{}.linkerFor(a)
eLinker := packetElementMapper{}.linkerFor(e)
b := aLinker.Prev()
eLinker.SetNext(a)
eLinker.SetPrev(b)
aLinker.SetPrev(e)
if b != nil {
packetElementMapper{}.linkerFor(b).SetNext(e)
} else {
l.head = e
}
}
// Remove removes e from l.
//
//go:nosplit
func (l *packetList) Remove(e *packet) {
linker := packetElementMapper{}.linkerFor(e)
prev := linker.Prev()
next := linker.Next()
if prev != nil {
packetElementMapper{}.linkerFor(prev).SetNext(next)
} else if l.head == e {
l.head = next
}
if next != nil {
packetElementMapper{}.linkerFor(next).SetPrev(prev)
} else if l.tail == e {
l.tail = prev
}
linker.SetNext(nil)
linker.SetPrev(nil)
}
// Entry is a default implementation of Linker. Users can add anonymous fields
// of this type to their structs to make them automatically implement the
// methods needed by List.
//
// +stateify savable
type packetEntry struct {
next *packet
prev *packet
}
// Next returns the entry that follows e in the list.
//
//go:nosplit
func (e *packetEntry) Next() *packet {
return e.next
}
// Prev returns the entry that precedes e in the list.
//
//go:nosplit
func (e *packetEntry) Prev() *packet {
return e.prev
}
// SetNext assigns 'entry' as the entry that follows e in the list.
//
//go:nosplit
func (e *packetEntry) SetNext(elem *packet) {
e.next = elem
}
// SetPrev assigns 'entry' as the entry that precedes e in the list.
//
//go:nosplit
func (e *packetEntry) SetPrev(elem *packet) {
e.prev = elem
}

View file

@ -0,0 +1,96 @@
package packet
import (
"reflect"
"github.com/sagernet/gvisor/pkg/sync"
"github.com/sagernet/gvisor/pkg/sync/locking"
)
// RWMutex is sync.RWMutex with the correctness validator.
type packetMmapRWMutex struct {
mu sync.RWMutex
}
// lockNames is a list of user-friendly lock names.
// Populated in init.
var packetMmaplockNames []string
// lockNameIndex is used as an index passed to NestedLock and NestedUnlock,
// referring to an index within lockNames.
// Values are specified using the "consts" field of go_template_instance.
type packetMmaplockNameIndex int
// DO NOT REMOVE: The following function automatically replaced with lock index constants.
// LOCK_NAME_INDEX_CONSTANTS
const ()
// Lock locks m.
// +checklocksignore
func (m *packetMmapRWMutex) Lock() {
locking.AddGLock(packetMmapprefixIndex, -1)
m.mu.Lock()
}
// NestedLock locks m knowing that another lock of the same type is held.
// +checklocksignore
func (m *packetMmapRWMutex) NestedLock(i packetMmaplockNameIndex) {
locking.AddGLock(packetMmapprefixIndex, int(i))
m.mu.Lock()
}
// Unlock unlocks m.
// +checklocksignore
func (m *packetMmapRWMutex) Unlock() {
m.mu.Unlock()
locking.DelGLock(packetMmapprefixIndex, -1)
}
// NestedUnlock unlocks m knowing that another lock of the same type is held.
// +checklocksignore
func (m *packetMmapRWMutex) NestedUnlock(i packetMmaplockNameIndex) {
m.mu.Unlock()
locking.DelGLock(packetMmapprefixIndex, int(i))
}
// RLock locks m for reading.
// +checklocksignore
func (m *packetMmapRWMutex) RLock() {
locking.AddGLock(packetMmapprefixIndex, -1)
m.mu.RLock()
}
// RUnlock undoes a single RLock call.
// +checklocksignore
func (m *packetMmapRWMutex) RUnlock() {
m.mu.RUnlock()
locking.DelGLock(packetMmapprefixIndex, -1)
}
// RLockBypass locks m for reading without executing the validator.
// +checklocksignore
func (m *packetMmapRWMutex) RLockBypass() {
m.mu.RLock()
}
// RUnlockBypass undoes a single RLockBypass call.
// +checklocksignore
func (m *packetMmapRWMutex) RUnlockBypass() {
m.mu.RUnlock()
}
// DowngradeLock atomically unlocks rw for writing and locks it for reading.
// +checklocksignore
func (m *packetMmapRWMutex) DowngradeLock() {
m.mu.DowngradeLock()
}
var packetMmapprefixIndex *locking.MutexClass
// DO NOT REMOVE: The following function is automatically replaced.
func packetMmapinitLockNames() {}
func init() {
packetMmapinitLockNames()
packetMmapprefixIndex = locking.NewMutexClass(reflect.TypeOf(packetMmapRWMutex{}), packetMmaplockNames)
}

View file

@ -0,0 +1,181 @@
// automatically generated by stateify.
package packet
import (
"context"
"github.com/sagernet/gvisor/pkg/state"
)
func (p *packet) StateTypeName() string {
return "pkg/tcpip/transport/packet.packet"
}
func (p *packet) StateFields() []string {
return []string{
"packetEntry",
"data",
"receivedAt",
"senderAddr",
"packetInfo",
}
}
func (p *packet) beforeSave() {}
// +checklocksignore
func (p *packet) StateSave(stateSinkObject state.Sink) {
p.beforeSave()
var receivedAtValue int64
receivedAtValue = p.saveReceivedAt()
stateSinkObject.SaveValue(2, receivedAtValue)
stateSinkObject.Save(0, &p.packetEntry)
stateSinkObject.Save(1, &p.data)
stateSinkObject.Save(3, &p.senderAddr)
stateSinkObject.Save(4, &p.packetInfo)
}
func (p *packet) afterLoad(context.Context) {}
// +checklocksignore
func (p *packet) StateLoad(ctx context.Context, stateSourceObject state.Source) {
stateSourceObject.Load(0, &p.packetEntry)
stateSourceObject.Load(1, &p.data)
stateSourceObject.Load(3, &p.senderAddr)
stateSourceObject.Load(4, &p.packetInfo)
stateSourceObject.LoadValue(2, new(int64), func(y any) { p.loadReceivedAt(ctx, y.(int64)) })
}
func (ep *endpoint) StateTypeName() string {
return "pkg/tcpip/transport/packet.endpoint"
}
func (ep *endpoint) StateFields() []string {
return []string{
"DefaultSocketOptionsHandler",
"stack",
"waiterQueue",
"cooked",
"ops",
"stats",
"rcvList",
"rcvBufSize",
"rcvClosed",
"rcvDisabled",
"closed",
"boundNetProto",
"boundNIC",
"lastError",
"packetMMapVersion",
"packetMMapReserve",
"packetMMapEp",
}
}
// +checklocksignore
func (ep *endpoint) StateSave(stateSinkObject state.Sink) {
ep.beforeSave()
stateSinkObject.Save(0, &ep.DefaultSocketOptionsHandler)
stateSinkObject.Save(1, &ep.stack)
stateSinkObject.Save(2, &ep.waiterQueue)
stateSinkObject.Save(3, &ep.cooked)
stateSinkObject.Save(4, &ep.ops)
stateSinkObject.Save(5, &ep.stats)
stateSinkObject.Save(6, &ep.rcvList)
stateSinkObject.Save(7, &ep.rcvBufSize)
stateSinkObject.Save(8, &ep.rcvClosed)
stateSinkObject.Save(9, &ep.rcvDisabled)
stateSinkObject.Save(10, &ep.closed)
stateSinkObject.Save(11, &ep.boundNetProto)
stateSinkObject.Save(12, &ep.boundNIC)
stateSinkObject.Save(13, &ep.lastError)
stateSinkObject.Save(14, &ep.packetMMapVersion)
stateSinkObject.Save(15, &ep.packetMMapReserve)
stateSinkObject.Save(16, &ep.packetMMapEp)
}
// +checklocksignore
func (ep *endpoint) StateLoad(ctx context.Context, stateSourceObject state.Source) {
stateSourceObject.Load(0, &ep.DefaultSocketOptionsHandler)
stateSourceObject.Load(1, &ep.stack)
stateSourceObject.Load(2, &ep.waiterQueue)
stateSourceObject.Load(3, &ep.cooked)
stateSourceObject.Load(4, &ep.ops)
stateSourceObject.Load(5, &ep.stats)
stateSourceObject.Load(6, &ep.rcvList)
stateSourceObject.Load(7, &ep.rcvBufSize)
stateSourceObject.Load(8, &ep.rcvClosed)
stateSourceObject.Load(9, &ep.rcvDisabled)
stateSourceObject.Load(10, &ep.closed)
stateSourceObject.Load(11, &ep.boundNetProto)
stateSourceObject.Load(12, &ep.boundNIC)
stateSourceObject.Load(13, &ep.lastError)
stateSourceObject.Load(14, &ep.packetMMapVersion)
stateSourceObject.Load(15, &ep.packetMMapReserve)
stateSourceObject.Load(16, &ep.packetMMapEp)
stateSourceObject.AfterLoad(func() { ep.afterLoad(ctx) })
}
func (l *packetList) StateTypeName() string {
return "pkg/tcpip/transport/packet.packetList"
}
func (l *packetList) StateFields() []string {
return []string{
"head",
"tail",
}
}
func (l *packetList) beforeSave() {}
// +checklocksignore
func (l *packetList) StateSave(stateSinkObject state.Sink) {
l.beforeSave()
stateSinkObject.Save(0, &l.head)
stateSinkObject.Save(1, &l.tail)
}
func (l *packetList) afterLoad(context.Context) {}
// +checklocksignore
func (l *packetList) StateLoad(ctx context.Context, stateSourceObject state.Source) {
stateSourceObject.Load(0, &l.head)
stateSourceObject.Load(1, &l.tail)
}
func (e *packetEntry) StateTypeName() string {
return "pkg/tcpip/transport/packet.packetEntry"
}
func (e *packetEntry) StateFields() []string {
return []string{
"next",
"prev",
}
}
func (e *packetEntry) beforeSave() {}
// +checklocksignore
func (e *packetEntry) StateSave(stateSinkObject state.Sink) {
e.beforeSave()
stateSinkObject.Save(0, &e.next)
stateSinkObject.Save(1, &e.prev)
}
func (e *packetEntry) afterLoad(context.Context) {}
// +checklocksignore
func (e *packetEntry) StateLoad(ctx context.Context, stateSourceObject state.Source) {
stateSourceObject.Load(0, &e.next)
stateSourceObject.Load(1, &e.prev)
}
func init() {
state.Register((*packet)(nil))
state.Register((*endpoint)(nil))
state.Register((*packetList)(nil))
state.Register((*packetEntry)(nil))
}