summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobert Tonic <btonic@users.noreply.github.com>2019-09-19 12:37:15 -0400
committerRobert Tonic <btonic@users.noreply.github.com>2019-09-19 12:37:15 -0400
commitac38a7ead0870118d27d570a8a98a90a7a225a12 (patch)
tree148be23cd23865cb8b586321d05389bf01c6d9a2
parentc2ae77a607b6e103545aa83e8f2c7c5bf649846f (diff)
Place the host UDS mounting behind --fsgofer-host-uds-allowed.
This commit allows the use of the `--fsgofer-host-uds-allowed` flag to enable mounting sockets and add the appropriate seccomp filters.
-rw-r--r--runsc/boot/config.go3
-rw-r--r--runsc/cmd/gofer.go25
-rw-r--r--runsc/container/container.go5
-rw-r--r--runsc/fsgofer/filter/config.go23
-rw-r--r--runsc/fsgofer/filter/filter.go12
-rw-r--r--runsc/fsgofer/fsgofer.go18
-rw-r--r--runsc/main.go66
7 files changed, 98 insertions, 54 deletions
diff --git a/runsc/boot/config.go b/runsc/boot/config.go
index 7ae0dd05d..954ad2c2a 100644
--- a/runsc/boot/config.go
+++ b/runsc/boot/config.go
@@ -138,6 +138,9 @@ type Config struct {
// Overlay is whether to wrap the root filesystem in an overlay.
Overlay bool
+ // fsGoferHostUDSAllowed enables the gofer to mount a host UDS
+ FSGoferHostUDSAllowed bool
+
// Network indicates what type of network to use.
Network NetworkType
diff --git a/runsc/cmd/gofer.go b/runsc/cmd/gofer.go
index 9faabf494..8e63c80e0 100644
--- a/runsc/cmd/gofer.go
+++ b/runsc/cmd/gofer.go
@@ -56,10 +56,11 @@ var goferCaps = &specs.LinuxCapabilities{
// Gofer implements subcommands.Command for the "gofer" command, which starts a
// filesystem gofer. This command should not be called directly.
type Gofer struct {
- bundleDir string
- ioFDs intFlags
- applyCaps bool
- setUpRoot bool
+ bundleDir string
+ ioFDs intFlags
+ applyCaps bool
+ hostUDSAllowed bool
+ setUpRoot bool
panicOnWrite bool
specFD int
@@ -86,6 +87,7 @@ func (g *Gofer) SetFlags(f *flag.FlagSet) {
f.StringVar(&g.bundleDir, "bundle", "", "path to the root of the bundle directory, defaults to the current directory")
f.Var(&g.ioFDs, "io-fds", "list of FDs to connect 9P servers. They must follow this order: root first, then mounts as defined in the spec")
f.BoolVar(&g.applyCaps, "apply-caps", true, "if true, apply capabilities to restrict what the Gofer process can do")
+ f.BoolVar(&g.hostUDSAllowed, "host-uds-allowed", false, "if true, allow the Gofer to mount a host UDS")
f.BoolVar(&g.panicOnWrite, "panic-on-write", false, "if true, panics on attempts to write to RO mounts. RW mounts are unnaffected")
f.BoolVar(&g.setUpRoot, "setup-root", true, "if true, set up an empty root for the process")
f.IntVar(&g.specFD, "spec-fd", -1, "required fd with the container spec")
@@ -180,8 +182,9 @@ func (g *Gofer) Execute(_ context.Context, f *flag.FlagSet, args ...interface{})
for _, m := range spec.Mounts {
if specutils.Is9PMount(m) {
cfg := fsgofer.Config{
- ROMount: isReadonlyMount(m.Options),
- PanicOnWrite: g.panicOnWrite,
+ ROMount: isReadonlyMount(m.Options),
+ PanicOnWrite: g.panicOnWrite,
+ HostUDSAllowed: g.hostUDSAllowed,
}
ap, err := fsgofer.NewAttachPoint(m.Destination, cfg)
if err != nil {
@@ -200,8 +203,14 @@ 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 err := filter.Install(); err != nil {
- Fatalf("installing seccomp filters: %v", err)
+ if g.hostUDSAllowed {
+ if err := filter.InstallUDS(); err != nil {
+ Fatalf("installing UDS seccomp filters: %v", err)
+ }
+ } else {
+ if err := filter.Install(); err != nil {
+ Fatalf("installing seccomp filters: %v", err)
+ }
}
runServers(ats, g.ioFDs)
diff --git a/runsc/container/container.go b/runsc/container/container.go
index bbb364214..ceadb38aa 100644
--- a/runsc/container/container.go
+++ b/runsc/container/container.go
@@ -941,6 +941,11 @@ func (c *Container) createGoferProcess(spec *specs.Spec, conf *boot.Config, bund
args = append(args, "--panic-on-write=true")
}
+ // Add support for mounting host UDS in the gofer
+ if conf.FSGoferHostUDSAllowed {
+ args = append(args, "--host-uds-allowed=true")
+ }
+
// Open the spec file to donate to the sandbox.
specFile, err := specutils.OpenSpec(bundleDir)
if err != nil {
diff --git a/runsc/fsgofer/filter/config.go b/runsc/fsgofer/filter/config.go
index 73407383d..8989cdb2f 100644
--- a/runsc/fsgofer/filter/config.go
+++ b/runsc/fsgofer/filter/config.go
@@ -26,16 +26,6 @@ import (
// allowedSyscalls is the set of syscalls executed by the gofer.
var allowedSyscalls = seccomp.SyscallRules{
syscall.SYS_ACCEPT: {},
- syscall.SYS_SOCKET: []seccomp.Rule{
- {
- seccomp.AllowValue(syscall.AF_UNIX),
- },
- },
- syscall.SYS_CONNECT: []seccomp.Rule{
- {
- seccomp.AllowAny{},
- },
- },
syscall.SYS_ARCH_PRCTL: []seccomp.Rule{
{seccomp.AllowValue(linux.ARCH_GET_FS)},
{seccomp.AllowValue(linux.ARCH_SET_FS)},
@@ -194,3 +184,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{},
+ },
+ },
+}
diff --git a/runsc/fsgofer/filter/filter.go b/runsc/fsgofer/filter/filter.go
index 65053415f..12ef19d18 100644
--- a/runsc/fsgofer/filter/filter.go
+++ b/runsc/fsgofer/filter/filter.go
@@ -31,3 +31,15 @@ func Install() error {
return seccomp.Install(s)
}
+
+// InstallUDS installs the standard Gofer seccomp filters along with filters
+// allowing the gofer to connect to a host UDS.
+func InstallUDS() error {
+ // Use the base syscall
+ s := allowedSyscalls
+
+ // Add additional filters required for connecting to the host's sockets.
+ s.Merge(udsSyscalls)
+
+ return seccomp.Install(s)
+}
diff --git a/runsc/fsgofer/fsgofer.go b/runsc/fsgofer/fsgofer.go
index 89171c811..d9f3ba8d6 100644
--- a/runsc/fsgofer/fsgofer.go
+++ b/runsc/fsgofer/fsgofer.go
@@ -85,6 +85,9 @@ type Config struct {
// PanicOnWrite panics on attempts to write to RO mounts.
PanicOnWrite bool
+
+ // HostUDS prevents
+ HostUDSAllowed bool
}
type attachPoint struct {
@@ -128,12 +131,21 @@ func (a *attachPoint) Attach() (p9.File, error) {
return nil, fmt.Errorf("stat 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; {
case fmtStat == syscall.S_IFSOCK:
+ // Check to see if the CLI option has been set to allow the UDS mount
+ if !a.conf.HostUDSAllowed {
+ return nil, fmt.Errorf("host UDS support is disabled")
+ }
+
// Attempt to open a connection. Bubble up the failures.
f, err = fd.OpenUnix(a.prefix)
if err != nil {
@@ -144,7 +156,7 @@ func (a *attachPoint) Attach() (p9.File, error) {
// Default to Read/Write permissions.
mode := syscall.O_RDWR
- // If the configuration is Read Only & the mount point is a directory,
+ // 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
@@ -157,9 +169,7 @@ func (a *attachPoint) Attach() (p9.File, error) {
}
}
- // Close the connection if the UDS is already attached.
- a.attachedMu.Lock()
- defer a.attachedMu.Unlock()
+ // Close the connection if already attached.
if a.attached {
f.Close()
return nil, fmt.Errorf("attach point already attached, prefix: %s", a.prefix)
diff --git a/runsc/main.go b/runsc/main.go
index c61583441..5eba949f6 100644
--- a/runsc/main.go
+++ b/runsc/main.go
@@ -63,17 +63,18 @@ var (
straceLogSize = flag.Uint("strace-log-size", 1024, "default size (in bytes) to log data argument blobs")
// Flags that control sandbox runtime behavior.
- platformName = flag.String("platform", "ptrace", "specifies which platform to use: ptrace (default), kvm")
- 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.")
- 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.")
- profile = flag.Bool("profile", false, "prepares the sandbox to use Golang profiler. Note that enabling profiler loosens the seccomp protection added to the sandbox (DO NOT USE IN PRODUCTION).")
- netRaw = flag.Bool("net-raw", false, "enable raw sockets. When false, raw sockets are disabled by removing CAP_NET_RAW from containers (`runsc exec` will still be able to utilize raw sockets). Raw sockets allow malicious containers to craft packets and potentially attack the network.")
- numNetworkChannels = flag.Int("num-network-channels", 1, "number of underlying channels(FDs) to use for network link endpoints.")
- rootless = flag.Bool("rootless", false, "it allows the sandbox to be started with a user that is not root. Sandbox and Gofer processes may run with same privileges as current user.")
+ platformName = flag.String("platform", "ptrace", "specifies which platform to use: ptrace (default), kvm")
+ 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.")
+ fsGoferHostUDSAllowed = flag.Bool("fsgofer-host-uds-allowed", 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.")
+ profile = flag.Bool("profile", false, "prepares the sandbox to use Golang profiler. Note that enabling profiler loosens the seccomp protection added to the sandbox (DO NOT USE IN PRODUCTION).")
+ netRaw = flag.Bool("net-raw", false, "enable raw sockets. When false, raw sockets are disabled by removing CAP_NET_RAW from containers (`runsc exec` will still be able to utilize raw sockets). Raw sockets allow malicious containers to craft packets and potentially attack the network.")
+ numNetworkChannels = flag.Int("num-network-channels", 1, "number of underlying channels(FDs) to use for network link endpoints.")
+ rootless = flag.Bool("rootless", false, "it allows the sandbox to be started with a user that is not root. Sandbox and Gofer processes may run with same privileges as current user.")
// Test flags, not to be used outside tests, ever.
testOnlyAllowRunAsCurrentUserWithoutChroot = flag.Bool("TESTONLY-unsafe-nonroot", false, "TEST ONLY; do not ever use! This skips many security measures that isolate the host from the sandbox.")
@@ -171,27 +172,28 @@ func main() {
// Create a new Config from the flags.
conf := &boot.Config{
- RootDir: *rootDir,
- Debug: *debug,
- LogFilename: *logFilename,
- LogFormat: *logFormat,
- DebugLog: *debugLog,
- DebugLogFormat: *debugLogFormat,
- FileAccess: fsAccess,
- Overlay: *overlay,
- Network: netType,
- GSO: *gso,
- LogPackets: *logPackets,
- Platform: platformType,
- Strace: *strace,
- StraceLogSize: *straceLogSize,
- WatchdogAction: wa,
- PanicSignal: *panicSignal,
- ProfileEnable: *profile,
- EnableRaw: *netRaw,
- NumNetworkChannels: *numNetworkChannels,
- Rootless: *rootless,
- AlsoLogToStderr: *alsoLogToStderr,
+ RootDir: *rootDir,
+ Debug: *debug,
+ LogFilename: *logFilename,
+ LogFormat: *logFormat,
+ DebugLog: *debugLog,
+ DebugLogFormat: *debugLogFormat,
+ FileAccess: fsAccess,
+ FSGoferHostUDSAllowed: *fsGoferHostUDSAllowed,
+ Overlay: *overlay,
+ Network: netType,
+ GSO: *gso,
+ LogPackets: *logPackets,
+ Platform: platformType,
+ Strace: *strace,
+ StraceLogSize: *straceLogSize,
+ WatchdogAction: wa,
+ PanicSignal: *panicSignal,
+ ProfileEnable: *profile,
+ EnableRaw: *netRaw,
+ NumNetworkChannels: *numNetworkChannels,
+ Rootless: *rootless,
+ AlsoLogToStderr: *alsoLogToStderr,
TestOnlyAllowRunAsCurrentUserWithoutChroot: *testOnlyAllowRunAsCurrentUserWithoutChroot,
}