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.
This commit is contained in:
parent
c2ae77a607
commit
ac38a7ead0
|
@ -138,6 +138,9 @@ type Config struct {
|
||||||
// Overlay is whether to wrap the root filesystem in an overlay.
|
// Overlay is whether to wrap the root filesystem in an overlay.
|
||||||
Overlay bool
|
Overlay bool
|
||||||
|
|
||||||
|
// fsGoferHostUDSAllowed enables the gofer to mount a host UDS
|
||||||
|
FSGoferHostUDSAllowed bool
|
||||||
|
|
||||||
// Network indicates what type of network to use.
|
// Network indicates what type of network to use.
|
||||||
Network NetworkType
|
Network NetworkType
|
||||||
|
|
||||||
|
|
|
@ -56,10 +56,11 @@ var goferCaps = &specs.LinuxCapabilities{
|
||||||
// Gofer implements subcommands.Command for the "gofer" command, which starts a
|
// Gofer implements subcommands.Command for the "gofer" command, which starts a
|
||||||
// filesystem gofer. This command should not be called directly.
|
// filesystem gofer. This command should not be called directly.
|
||||||
type Gofer struct {
|
type Gofer struct {
|
||||||
bundleDir string
|
bundleDir string
|
||||||
ioFDs intFlags
|
ioFDs intFlags
|
||||||
applyCaps bool
|
applyCaps bool
|
||||||
setUpRoot bool
|
hostUDSAllowed bool
|
||||||
|
setUpRoot bool
|
||||||
|
|
||||||
panicOnWrite bool
|
panicOnWrite bool
|
||||||
specFD int
|
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.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.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.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.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.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")
|
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 {
|
for _, m := range spec.Mounts {
|
||||||
if specutils.Is9PMount(m) {
|
if specutils.Is9PMount(m) {
|
||||||
cfg := fsgofer.Config{
|
cfg := fsgofer.Config{
|
||||||
ROMount: isReadonlyMount(m.Options),
|
ROMount: isReadonlyMount(m.Options),
|
||||||
PanicOnWrite: g.panicOnWrite,
|
PanicOnWrite: g.panicOnWrite,
|
||||||
|
HostUDSAllowed: g.hostUDSAllowed,
|
||||||
}
|
}
|
||||||
ap, err := fsgofer.NewAttachPoint(m.Destination, cfg)
|
ap, err := fsgofer.NewAttachPoint(m.Destination, cfg)
|
||||||
if err != nil {
|
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))
|
Fatalf("too many FDs passed for mounts. mounts: %d, FDs: %d", mountIdx, len(g.ioFDs))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := filter.Install(); err != nil {
|
if g.hostUDSAllowed {
|
||||||
Fatalf("installing seccomp filters: %v", err)
|
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)
|
runServers(ats, g.ioFDs)
|
||||||
|
|
|
@ -941,6 +941,11 @@ func (c *Container) createGoferProcess(spec *specs.Spec, conf *boot.Config, bund
|
||||||
args = append(args, "--panic-on-write=true")
|
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.
|
// Open the spec file to donate to the sandbox.
|
||||||
specFile, err := specutils.OpenSpec(bundleDir)
|
specFile, err := specutils.OpenSpec(bundleDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -26,16 +26,6 @@ import (
|
||||||
// allowedSyscalls is the set of syscalls executed by the gofer.
|
// allowedSyscalls is the set of syscalls executed by the gofer.
|
||||||
var allowedSyscalls = seccomp.SyscallRules{
|
var allowedSyscalls = seccomp.SyscallRules{
|
||||||
syscall.SYS_ACCEPT: {},
|
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{
|
syscall.SYS_ARCH_PRCTL: []seccomp.Rule{
|
||||||
{seccomp.AllowValue(linux.ARCH_GET_FS)},
|
{seccomp.AllowValue(linux.ARCH_GET_FS)},
|
||||||
{seccomp.AllowValue(linux.ARCH_SET_FS)},
|
{seccomp.AllowValue(linux.ARCH_SET_FS)},
|
||||||
|
@ -194,3 +184,16 @@ var allowedSyscalls = seccomp.SyscallRules{
|
||||||
syscall.SYS_UTIMENSAT: {},
|
syscall.SYS_UTIMENSAT: {},
|
||||||
syscall.SYS_WRITE: {},
|
syscall.SYS_WRITE: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var udsSyscalls = seccomp.SyscallRules{
|
||||||
|
syscall.SYS_SOCKET: []seccomp.Rule{
|
||||||
|
{
|
||||||
|
seccomp.AllowValue(syscall.AF_UNIX),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
syscall.SYS_CONNECT: []seccomp.Rule{
|
||||||
|
{
|
||||||
|
seccomp.AllowAny{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -31,3 +31,15 @@ func Install() error {
|
||||||
|
|
||||||
return seccomp.Install(s)
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -85,6 +85,9 @@ type Config struct {
|
||||||
|
|
||||||
// PanicOnWrite panics on attempts to write to RO mounts.
|
// PanicOnWrite panics on attempts to write to RO mounts.
|
||||||
PanicOnWrite bool
|
PanicOnWrite bool
|
||||||
|
|
||||||
|
// HostUDS prevents
|
||||||
|
HostUDSAllowed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type attachPoint struct {
|
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)
|
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
|
// Hold the file descriptor we are converting into a p9.File
|
||||||
var f *fd.FD
|
var f *fd.FD
|
||||||
|
|
||||||
// Apply the S_IFMT bitmask so we can detect file type appropriately
|
// Apply the S_IFMT bitmask so we can detect file type appropriately
|
||||||
switch fmtStat := stat.Mode & syscall.S_IFMT; {
|
switch fmtStat := stat.Mode & syscall.S_IFMT; {
|
||||||
case fmtStat == syscall.S_IFSOCK:
|
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.
|
// Attempt to open a connection. Bubble up the failures.
|
||||||
f, err = fd.OpenUnix(a.prefix)
|
f, err = fd.OpenUnix(a.prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -144,7 +156,7 @@ func (a *attachPoint) Attach() (p9.File, error) {
|
||||||
// Default to Read/Write permissions.
|
// Default to Read/Write permissions.
|
||||||
mode := syscall.O_RDWR
|
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.
|
// set the mode to Read Only.
|
||||||
if a.conf.ROMount || fmtStat == syscall.S_IFDIR {
|
if a.conf.ROMount || fmtStat == syscall.S_IFDIR {
|
||||||
mode = syscall.O_RDONLY
|
mode = syscall.O_RDONLY
|
||||||
|
@ -157,9 +169,7 @@ func (a *attachPoint) Attach() (p9.File, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the connection if the UDS is already attached.
|
// Close the connection if already attached.
|
||||||
a.attachedMu.Lock()
|
|
||||||
defer a.attachedMu.Unlock()
|
|
||||||
if a.attached {
|
if a.attached {
|
||||||
f.Close()
|
f.Close()
|
||||||
return nil, fmt.Errorf("attach point already attached, prefix: %s", a.prefix)
|
return nil, fmt.Errorf("attach point already attached, prefix: %s", a.prefix)
|
||||||
|
|
|
@ -63,17 +63,18 @@ var (
|
||||||
straceLogSize = flag.Uint("strace-log-size", 1024, "default size (in bytes) to log data argument blobs")
|
straceLogSize = flag.Uint("strace-log-size", 1024, "default size (in bytes) to log data argument blobs")
|
||||||
|
|
||||||
// Flags that control sandbox runtime behavior.
|
// Flags that control sandbox runtime behavior.
|
||||||
platformName = flag.String("platform", "ptrace", "specifies which platform to use: ptrace (default), kvm")
|
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.")
|
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")
|
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.")
|
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.")
|
fsGoferHostUDSAllowed = flag.Bool("fsgofer-host-uds-allowed", false, "Allow the gofer to mount Unix Domain Sockets.")
|
||||||
watchdogAction = flag.String("watchdog-action", "log", "sets what action the watchdog takes when triggered: log (default), panic.")
|
overlay = flag.Bool("overlay", false, "wrap filesystem mounts with writable overlay. All modifications are stored in memory inside the sandbox.")
|
||||||
panicSignal = flag.Int("panic-signal", -1, "register signal handling that panics. Usually set to SIGUSR2(12) to troubleshoot hangs. -1 disables it.")
|
watchdogAction = flag.String("watchdog-action", "log", "sets what action the watchdog takes when triggered: log (default), panic.")
|
||||||
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).")
|
panicSignal = flag.Int("panic-signal", -1, "register signal handling that panics. Usually set to SIGUSR2(12) to troubleshoot hangs. -1 disables it.")
|
||||||
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.")
|
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).")
|
||||||
numNetworkChannels = flag.Int("num-network-channels", 1, "number of underlying channels(FDs) to use for network link endpoints.")
|
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.")
|
||||||
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.")
|
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.
|
// 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.")
|
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.
|
// Create a new Config from the flags.
|
||||||
conf := &boot.Config{
|
conf := &boot.Config{
|
||||||
RootDir: *rootDir,
|
RootDir: *rootDir,
|
||||||
Debug: *debug,
|
Debug: *debug,
|
||||||
LogFilename: *logFilename,
|
LogFilename: *logFilename,
|
||||||
LogFormat: *logFormat,
|
LogFormat: *logFormat,
|
||||||
DebugLog: *debugLog,
|
DebugLog: *debugLog,
|
||||||
DebugLogFormat: *debugLogFormat,
|
DebugLogFormat: *debugLogFormat,
|
||||||
FileAccess: fsAccess,
|
FileAccess: fsAccess,
|
||||||
Overlay: *overlay,
|
FSGoferHostUDSAllowed: *fsGoferHostUDSAllowed,
|
||||||
Network: netType,
|
Overlay: *overlay,
|
||||||
GSO: *gso,
|
Network: netType,
|
||||||
LogPackets: *logPackets,
|
GSO: *gso,
|
||||||
Platform: platformType,
|
LogPackets: *logPackets,
|
||||||
Strace: *strace,
|
Platform: platformType,
|
||||||
StraceLogSize: *straceLogSize,
|
Strace: *strace,
|
||||||
WatchdogAction: wa,
|
StraceLogSize: *straceLogSize,
|
||||||
PanicSignal: *panicSignal,
|
WatchdogAction: wa,
|
||||||
ProfileEnable: *profile,
|
PanicSignal: *panicSignal,
|
||||||
EnableRaw: *netRaw,
|
ProfileEnable: *profile,
|
||||||
NumNetworkChannels: *numNetworkChannels,
|
EnableRaw: *netRaw,
|
||||||
Rootless: *rootless,
|
NumNetworkChannels: *numNetworkChannels,
|
||||||
AlsoLogToStderr: *alsoLogToStderr,
|
Rootless: *rootless,
|
||||||
|
AlsoLogToStderr: *alsoLogToStderr,
|
||||||
|
|
||||||
TestOnlyAllowRunAsCurrentUserWithoutChroot: *testOnlyAllowRunAsCurrentUserWithoutChroot,
|
TestOnlyAllowRunAsCurrentUserWithoutChroot: *testOnlyAllowRunAsCurrentUserWithoutChroot,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue