mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Merge pull request #765 from trailofbits:uds_support
PiperOrigin-RevId: 271235134
This commit is contained in:
@@ -8,6 +8,9 @@ go_library(
|
||||
srcs = ["fd.go"],
|
||||
importpath = "gvisor.dev/gvisor/pkg/fd",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/unet",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/unet"
|
||||
)
|
||||
|
||||
// ReadWriter implements io.ReadWriter, io.ReaderAt, and io.WriterAt for fd. It
|
||||
@@ -185,6 +187,12 @@ func OpenAt(dir *FD, path string, flags int, mode uint32) (*FD, error) {
|
||||
return New(f), nil
|
||||
}
|
||||
|
||||
// DialUnix connects to a Unix Domain Socket and return the file descriptor.
|
||||
func DialUnix(path string) (*FD, error) {
|
||||
socket, err := unet.Connect(path, false)
|
||||
return New(socket.FD()), err
|
||||
}
|
||||
|
||||
// Close closes the file descriptor contained in the FD.
|
||||
//
|
||||
// Close is safe to call multiple times, but will return an error after the
|
||||
|
||||
@@ -167,6 +167,9 @@ type Config struct {
|
||||
// Overlay is whether to wrap the root filesystem in an overlay.
|
||||
Overlay bool
|
||||
|
||||
// FSGoferHostUDS enables the gofer to mount a host UDS.
|
||||
FSGoferHostUDS bool
|
||||
|
||||
// Network indicates what type of network to use.
|
||||
Network NetworkType
|
||||
|
||||
@@ -253,6 +256,7 @@ func (c *Config) ToFlags() []string {
|
||||
"--debug-log-format=" + c.DebugLogFormat,
|
||||
"--file-access=" + c.FileAccess.String(),
|
||||
"--overlay=" + strconv.FormatBool(c.Overlay),
|
||||
"--fsgofer-host-uds=" + strconv.FormatBool(c.FSGoferHostUDS),
|
||||
"--network=" + c.Network.String(),
|
||||
"--log-packets=" + strconv.FormatBool(c.LogPackets),
|
||||
"--platform=" + c.Platform,
|
||||
|
||||
@@ -182,6 +182,7 @@ func (g *Gofer) Execute(_ context.Context, f *flag.FlagSet, args ...interface{})
|
||||
cfg := fsgofer.Config{
|
||||
ROMount: isReadonlyMount(m.Options),
|
||||
PanicOnWrite: g.panicOnWrite,
|
||||
HostUDS: conf.FSGoferHostUDS,
|
||||
}
|
||||
ap, err := fsgofer.NewAttachPoint(m.Destination, cfg)
|
||||
if err != nil {
|
||||
@@ -200,6 +201,10 @@ func (g *Gofer) Execute(_ context.Context, f *flag.FlagSet, args ...interface{})
|
||||
Fatalf("too many FDs passed for mounts. mounts: %d, FDs: %d", mountIdx, len(g.ioFDs))
|
||||
}
|
||||
|
||||
if conf.FSGoferHostUDS {
|
||||
filter.InstallUDSFilters()
|
||||
}
|
||||
|
||||
if err := filter.Install(); err != nil {
|
||||
Fatalf("installing seccomp filters: %v", err)
|
||||
}
|
||||
|
||||
@@ -214,3 +214,16 @@ var allowedSyscalls = seccomp.SyscallRules{
|
||||
syscall.SYS_UTIMENSAT: {},
|
||||
syscall.SYS_WRITE: {},
|
||||
}
|
||||
|
||||
var udsSyscalls = seccomp.SyscallRules{
|
||||
syscall.SYS_SOCKET: []seccomp.Rule{
|
||||
{
|
||||
seccomp.AllowValue(syscall.AF_UNIX),
|
||||
},
|
||||
},
|
||||
syscall.SYS_CONNECT: []seccomp.Rule{
|
||||
{
|
||||
seccomp.AllowAny{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -23,11 +23,16 @@ import (
|
||||
|
||||
// Install installs seccomp filters.
|
||||
func Install() error {
|
||||
s := allowedSyscalls
|
||||
|
||||
// Set of additional filters used by -race and -msan. Returns empty
|
||||
// when not enabled.
|
||||
s.Merge(instrumentationFilters())
|
||||
allowedSyscalls.Merge(instrumentationFilters())
|
||||
|
||||
return seccomp.Install(s)
|
||||
return seccomp.Install(allowedSyscalls)
|
||||
}
|
||||
|
||||
// InstallUDSFilters extends the allowed syscalls to include those necessary for
|
||||
// connecting to a host UDS.
|
||||
func InstallUDSFilters() {
|
||||
// Add additional filters required for connecting to the host's sockets.
|
||||
allowedSyscalls.Merge(udsSyscalls)
|
||||
}
|
||||
|
||||
+52
-11
@@ -21,6 +21,7 @@
|
||||
package fsgofer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@@ -54,6 +55,7 @@ const (
|
||||
regular fileType = iota
|
||||
directory
|
||||
symlink
|
||||
socket
|
||||
unknown
|
||||
)
|
||||
|
||||
@@ -66,6 +68,8 @@ func (f fileType) String() string {
|
||||
return "directory"
|
||||
case symlink:
|
||||
return "symlink"
|
||||
case socket:
|
||||
return "socket"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
@@ -82,6 +86,9 @@ type Config struct {
|
||||
|
||||
// PanicOnWrite panics on attempts to write to RO mounts.
|
||||
PanicOnWrite bool
|
||||
|
||||
// HostUDS signals whether the gofer can mount a host's UDS.
|
||||
HostUDS bool
|
||||
}
|
||||
|
||||
type attachPoint struct {
|
||||
@@ -124,24 +131,52 @@ func (a *attachPoint) Attach() (p9.File, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stat file %q, err: %v", a.prefix, err)
|
||||
}
|
||||
mode := syscall.O_RDWR
|
||||
if a.conf.ROMount || (stat.Mode&syscall.S_IFMT) == syscall.S_IFDIR {
|
||||
mode = syscall.O_RDONLY
|
||||
}
|
||||
|
||||
// Open the root directory.
|
||||
f, err := fd.Open(a.prefix, openFlags|mode, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open file %q, err: %v", a.prefix, err)
|
||||
}
|
||||
|
||||
// Acquire the attach point lock.
|
||||
a.attachedMu.Lock()
|
||||
defer a.attachedMu.Unlock()
|
||||
|
||||
// Hold the file descriptor we are converting into a p9.File.
|
||||
var f *fd.FD
|
||||
|
||||
// Apply the S_IFMT bitmask so we can detect file type appropriately.
|
||||
switch fmtStat := stat.Mode & syscall.S_IFMT; fmtStat {
|
||||
case syscall.S_IFSOCK:
|
||||
// Check to see if the CLI option has been set to allow the UDS mount.
|
||||
if !a.conf.HostUDS {
|
||||
return nil, errors.New("host UDS support is disabled")
|
||||
}
|
||||
|
||||
// Attempt to open a connection. Bubble up the failures.
|
||||
f, err = fd.DialUnix(a.prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
// Default to Read/Write permissions.
|
||||
mode := syscall.O_RDWR
|
||||
|
||||
// If the configuration is Read Only or the mount point is a directory,
|
||||
// set the mode to Read Only.
|
||||
if a.conf.ROMount || fmtStat == syscall.S_IFDIR {
|
||||
mode = syscall.O_RDONLY
|
||||
}
|
||||
|
||||
// Open the mount point & capture the FD.
|
||||
f, err = fd.Open(a.prefix, openFlags|mode, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open file %q, err: %v", a.prefix, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Close the connection if already attached.
|
||||
if a.attached {
|
||||
f.Close()
|
||||
return nil, fmt.Errorf("attach point already attached, prefix: %s", a.prefix)
|
||||
}
|
||||
|
||||
// Return a localFile object to the caller with the UDS FD included.
|
||||
rv, err := newLocalFile(a, f, a.prefix, stat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -304,6 +339,8 @@ func getSupportedFileType(stat syscall.Stat_t) (fileType, error) {
|
||||
ft = directory
|
||||
case syscall.S_IFLNK:
|
||||
ft = symlink
|
||||
case syscall.S_IFSOCK:
|
||||
ft = socket
|
||||
default:
|
||||
return unknown, syscall.EPERM
|
||||
}
|
||||
@@ -1026,7 +1063,11 @@ func (l *localFile) Flush() error {
|
||||
|
||||
// Connect implements p9.File.
|
||||
func (l *localFile) Connect(p9.ConnectFlags) (*fd.FD, error) {
|
||||
return nil, syscall.ECONNREFUSED
|
||||
// Check to see if the CLI option has been set to allow the UDS mount.
|
||||
if !l.attachPoint.conf.HostUDS {
|
||||
return nil, errors.New("host UDS support is disabled")
|
||||
}
|
||||
return fd.DialUnix(l.hostPath)
|
||||
}
|
||||
|
||||
// Close implements p9.File.
|
||||
|
||||
@@ -68,6 +68,7 @@ var (
|
||||
network = flag.String("network", "sandbox", "specifies which network to use: sandbox (default), host, none. Using network inside the sandbox is more secure because it's isolated from the host network.")
|
||||
gso = flag.Bool("gso", true, "enable generic segmenation offload")
|
||||
fileAccess = flag.String("file-access", "exclusive", "specifies which filesystem to use for the root mount: exclusive (default), shared. Volume mounts are always shared.")
|
||||
fsGoferHostUDS = flag.Bool("fsgofer-host-uds", false, "Allow the gofer to mount Unix Domain Sockets.")
|
||||
overlay = flag.Bool("overlay", false, "wrap filesystem mounts with writable overlay. All modifications are stored in memory inside the sandbox.")
|
||||
watchdogAction = flag.String("watchdog-action", "log", "sets what action the watchdog takes when triggered: log (default), panic.")
|
||||
panicSignal = flag.Int("panic-signal", -1, "register signal handling that panics. Usually set to SIGUSR2(12) to troubleshoot hangs. -1 disables it.")
|
||||
@@ -195,6 +196,7 @@ func main() {
|
||||
DebugLog: *debugLog,
|
||||
DebugLogFormat: *debugLogFormat,
|
||||
FileAccess: fsAccess,
|
||||
FSGoferHostUDS: *fsGoferHostUDS,
|
||||
Overlay: *overlay,
|
||||
Network: netType,
|
||||
GSO: *gso,
|
||||
|
||||
Reference in New Issue
Block a user