Merge pull request #765 from trailofbits:uds_support

PiperOrigin-RevId: 271235134
This commit is contained in:
gVisor bot
2019-09-25 16:44:22 -07:00
8 changed files with 96 additions and 15 deletions
+3
View File
@@ -8,6 +8,9 @@ go_library(
srcs = ["fd.go"],
importpath = "gvisor.dev/gvisor/pkg/fd",
visibility = ["//visibility:public"],
deps = [
"//pkg/unet",
],
)
go_test(
+8
View File
@@ -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
+4
View File
@@ -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,
+5
View File
@@ -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)
}
+13
View File
@@ -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{},
},
},
}
+9 -4
View File
@@ -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
View File
@@ -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.
+2
View 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,