mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Fixes #9932. When Go is able to detect `io.Copy()` from a TCP socket or `AF_UNIX` stream socket to a TCP socket, it attempts to implement the copy as a `splice(2)` from the source to a pipe, followed by a `splice(2)` from the pipe to the destination [1] (since `splice(2)` requires that one of the endpoints be a pipe); the size of the pipe is set to 1 MB [2] (from a default of 64 KB [3]) to reduce the number of splice syscalls required. In gVisor, a bug causes each splice syscall from pipe to TCP socket to repeatedly read the *first* 64 KB [4] of the pipe's data (when it contains more than 64 KB of data) rather than *successive* chunks of 64 KB. To fix this, advance pipe state by calling `Pipe.consumeLocked()` immediately after `Pipe.peekLocked()`. Also defensively check that such FDs call `Pipe.(usermem.IO)` methods on sequential addresses, and change `fuse.deviceFD.Write()` to have this property. [1] Go: `net/tcpsock_posix.go:TCPConn.readFrom()` => `net/splice_linux.go:splice()` => `internal/poll/splice_linux.go:Splice()` [2] Go: `internal/poll/splice_linux.go:newPipe()` => `maxSpliceSize` [3] `pkg/kernel/pipe/pipe.go:DefaultPipeSize` [4] `pkg/tcpip/transport/tcp/endpoint.go:endpoint.Write()` => `endpoint.queueSegment()` => `endpoint.readFromPayloader()` => `pkg/buffer/buffer.go:Buffer.WriteFromReader()` => `pkg/buffer/chunk.go:MaxChunkSize` PiperOrigin-RevId: 603151951
79 lines
1.6 KiB
Python
79 lines
1.6 KiB
Python
load("//pkg/sync/locking:locking.bzl", "declare_mutex")
|
|
load("//tools:defs.bzl", "go_library", "go_test")
|
|
|
|
package(
|
|
default_applicable_licenses = ["//:license"],
|
|
licenses = ["notice"],
|
|
)
|
|
|
|
declare_mutex(
|
|
name = "vfs_mutex",
|
|
out = "vfs_mutex.go",
|
|
package = "pipe",
|
|
prefix = "vfs",
|
|
)
|
|
|
|
declare_mutex(
|
|
name = "pipe_mutex",
|
|
out = "pipe_mutex.go",
|
|
nested_lock_names = ["pipe"],
|
|
package = "pipe",
|
|
prefix = "pipe",
|
|
)
|
|
|
|
declare_mutex(
|
|
name = "inode_mutex",
|
|
out = "inode_mutex.go",
|
|
package = "pipe",
|
|
prefix = "inode",
|
|
)
|
|
|
|
go_library(
|
|
name = "pipe",
|
|
srcs = [
|
|
"inode_mutex.go",
|
|
"pipe.go",
|
|
"pipe_mutex.go",
|
|
"pipe_unsafe.go",
|
|
"pipe_util.go",
|
|
"save_restore.go",
|
|
"vfs.go",
|
|
],
|
|
visibility = ["//pkg/sentry:internal"],
|
|
deps = [
|
|
"//pkg/abi/linux",
|
|
"//pkg/atomicbitops",
|
|
"//pkg/context",
|
|
"//pkg/errors/linuxerr",
|
|
"//pkg/hostarch",
|
|
"//pkg/log",
|
|
"//pkg/marshal/primitive",
|
|
"//pkg/safemem",
|
|
"//pkg/sentry/arch",
|
|
"//pkg/sentry/fsutil",
|
|
"//pkg/sentry/vfs",
|
|
"//pkg/sync",
|
|
"//pkg/sync/locking",
|
|
"//pkg/usermem",
|
|
"//pkg/waiter",
|
|
"@org_golang_x_sys//unix:go_default_library",
|
|
],
|
|
)
|
|
|
|
go_test(
|
|
name = "pipe_test",
|
|
size = "small",
|
|
srcs = [
|
|
"pipe_test.go",
|
|
],
|
|
library = ":pipe",
|
|
deps = [
|
|
"//pkg/context",
|
|
"//pkg/errors/linuxerr",
|
|
"//pkg/sentry/contexttest",
|
|
"//pkg/sentry/vfs",
|
|
"//pkg/usermem",
|
|
"//pkg/waiter",
|
|
],
|
|
)
|