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:
commit
2c4ae3b0a4
712 changed files with 185689 additions and 0 deletions
166
pkg/flipcall/packet_window.go
Normal file
166
pkg/flipcall/packet_window.go
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
// 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 flipcall
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/bits"
|
||||
"os"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/abi/linux"
|
||||
"github.com/sagernet/gvisor/pkg/memutil"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
pageSize = os.Getpagesize()
|
||||
pageMask = pageSize - 1
|
||||
)
|
||||
|
||||
func init() {
|
||||
if bits.OnesCount(uint(pageSize)) != 1 {
|
||||
// This is depended on by roundUpToPage().
|
||||
panic(fmt.Sprintf("system page size (%d) is not a power of 2", pageSize))
|
||||
}
|
||||
if uintptr(pageSize) < PacketHeaderBytes {
|
||||
// This is required since Endpoint.Init() imposes a minimum packet
|
||||
// window size of 1 page.
|
||||
panic(fmt.Sprintf("system page size (%d) is less than packet header size (%d)", pageSize, PacketHeaderBytes))
|
||||
}
|
||||
}
|
||||
|
||||
// PacketWindowDescriptor represents a packet window, a range of pages in a
|
||||
// shared memory file that is used to exchange packets between partner
|
||||
// Endpoints.
|
||||
type PacketWindowDescriptor struct {
|
||||
// FD is the file descriptor representing the shared memory file.
|
||||
FD int
|
||||
|
||||
// Offset is the offset into the shared memory file at which the packet
|
||||
// window begins.
|
||||
Offset int64
|
||||
|
||||
// Length is the size of the packet window in bytes.
|
||||
Length int
|
||||
}
|
||||
|
||||
// PacketWindowLengthForDataCap returns the minimum packet window size required
|
||||
// to accommodate datagrams of the given size in bytes.
|
||||
func PacketWindowLengthForDataCap(dataCap uint32) int {
|
||||
return roundUpToPage(int(dataCap) + int(PacketHeaderBytes))
|
||||
}
|
||||
|
||||
func roundUpToPage(x int) int {
|
||||
return (x + pageMask) &^ pageMask
|
||||
}
|
||||
|
||||
// A PacketWindowAllocator owns a shared memory file, and allocates packet
|
||||
// windows from it.
|
||||
type PacketWindowAllocator struct {
|
||||
fd int
|
||||
nextAlloc int64
|
||||
fileSize int64
|
||||
}
|
||||
|
||||
// Init must be called on zero-value PacketWindowAllocators before first use.
|
||||
// If it succeeds, Destroy() must be called once the PacketWindowAllocator is
|
||||
// no longer in use.
|
||||
func (pwa *PacketWindowAllocator) Init() error {
|
||||
fd, err := memutil.CreateMemFD("flipcall_packet_windows", linux.MFD_CLOEXEC|linux.MFD_ALLOW_SEALING)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create memfd: %v", err)
|
||||
}
|
||||
// Apply F_SEAL_SHRINK to prevent either party from causing SIGBUS in the
|
||||
// other by truncating the file, and F_SEAL_SEAL to prevent either party
|
||||
// from applying F_SEAL_GROW or F_SEAL_WRITE.
|
||||
if _, _, e := unix.RawSyscall(unix.SYS_FCNTL, uintptr(fd), linux.F_ADD_SEALS, linux.F_SEAL_SHRINK|linux.F_SEAL_SEAL); e != 0 {
|
||||
unix.Close(fd)
|
||||
return fmt.Errorf("failed to apply memfd seals: %v", e)
|
||||
}
|
||||
pwa.fd = fd
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewPacketWindowAllocator is a convenience function that returns an
|
||||
// initialized PacketWindowAllocator allocated on the heap.
|
||||
func NewPacketWindowAllocator() (*PacketWindowAllocator, error) {
|
||||
var pwa PacketWindowAllocator
|
||||
if err := pwa.Init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pwa, nil
|
||||
}
|
||||
|
||||
// Destroy releases resources owned by pwa. This invalidates file descriptors
|
||||
// previously returned by pwa.FD() and pwd.Allocate().
|
||||
func (pwa *PacketWindowAllocator) Destroy() {
|
||||
unix.Close(pwa.fd)
|
||||
}
|
||||
|
||||
// FD represents the file descriptor of the shared memory file backing pwa.
|
||||
func (pwa *PacketWindowAllocator) FD() int {
|
||||
return pwa.fd
|
||||
}
|
||||
|
||||
// Allocate allocates a new packet window of at least the given size and
|
||||
// returns a PacketWindowDescriptor representing it.
|
||||
//
|
||||
// Preconditions: size > 0.
|
||||
func (pwa *PacketWindowAllocator) Allocate(size int) (PacketWindowDescriptor, error) {
|
||||
if size <= 0 {
|
||||
return PacketWindowDescriptor{}, fmt.Errorf("invalid size: %d", size)
|
||||
}
|
||||
// Page-align size to ensure that pwa.nextAlloc remains page-aligned.
|
||||
size = roundUpToPage(size)
|
||||
if size <= 0 {
|
||||
return PacketWindowDescriptor{}, fmt.Errorf("size %d overflows after rounding up to page size", size)
|
||||
}
|
||||
end := pwa.nextAlloc + int64(size) // overflow checked by ensureFileSize
|
||||
if err := pwa.ensureFileSize(end); err != nil {
|
||||
return PacketWindowDescriptor{}, err
|
||||
}
|
||||
start := pwa.nextAlloc
|
||||
pwa.nextAlloc = end
|
||||
return PacketWindowDescriptor{
|
||||
FD: pwa.FD(),
|
||||
Offset: start,
|
||||
Length: size,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (pwa *PacketWindowAllocator) ensureFileSize(min int64) error {
|
||||
if min <= 0 {
|
||||
return fmt.Errorf("file size would overflow")
|
||||
}
|
||||
if pwa.fileSize >= min {
|
||||
return nil
|
||||
}
|
||||
newSize := 2 * pwa.fileSize
|
||||
if newSize == 0 {
|
||||
newSize = int64(pageSize)
|
||||
}
|
||||
for newSize < min {
|
||||
newNewSize := newSize * 2
|
||||
if newNewSize <= 0 {
|
||||
return fmt.Errorf("file size would overflow")
|
||||
}
|
||||
newSize = newNewSize
|
||||
}
|
||||
if err := unix.Ftruncate(pwa.FD(), newSize); err != nil {
|
||||
return fmt.Errorf("ftruncate failed: %v", err)
|
||||
}
|
||||
pwa.fileSize = newSize
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue