summaryrefslogtreecommitdiffhomepage
path: root/runsc
diff options
context:
space:
mode:
Diffstat (limited to 'runsc')
-rw-r--r--runsc/boot/config.go5
-rw-r--r--runsc/sandbox/sandbox.go33
-rw-r--r--runsc/specutils/BUILD1
-rw-r--r--runsc/specutils/namespace.go14
-rw-r--r--runsc/test/testutil/testutil.go15
5 files changed, 59 insertions, 9 deletions
diff --git a/runsc/boot/config.go b/runsc/boot/config.go
index 212f5b003..87a47dd0b 100644
--- a/runsc/boot/config.go
+++ b/runsc/boot/config.go
@@ -213,6 +213,11 @@ type Config struct {
// PanicSignal register signal handling that panics. Usually set to
// SIGUSR2(12) to troubleshoot hangs. -1 disables it.
PanicSignal int
+
+ // TestOnlyAllowRunAsCurrentUser should only be used in tests. It
+ // allows runsc to start the sandbox process as the current user if we
+ // do not have capability to set uid/gid to another user.
+ TestOnlyAllowRunAsCurrentUser bool
}
// ToFlags returns a slice of flags that correspond to the given Config.
diff --git a/runsc/sandbox/sandbox.go b/runsc/sandbox/sandbox.go
index e0fadefcd..dd5a0aa56 100644
--- a/runsc/sandbox/sandbox.go
+++ b/runsc/sandbox/sandbox.go
@@ -373,8 +373,8 @@ func (s *Sandbox) createSandboxProcess(spec *specs.Spec, conf *boot.Config, bund
// User namespace depends on the following options:
// - Host network/filesystem: requires to run inside the user namespace
// specified in the spec or the current namespace if none is configured.
- // - Gofer: when using a Gofer, the sandbox process can run isolated in an
- // empty namespace.
+ // - Gofer: when using a Gofer, the sandbox process can run isolated in a
+ // new user namespace with only the "nobody" user and group.
if conf.Network == boot.NetworkHost || conf.FileAccess == boot.FileAccessDirect {
if userns, ok := specutils.GetNS(specs.UserNamespace, spec); ok {
log.Infof("Sandbox will be started in container's user namespace: %+v", userns)
@@ -391,6 +391,34 @@ func (s *Sandbox) createSandboxProcess(spec *specs.Spec, conf *boot.Config, bund
} else {
log.Infof("Sandbox will be started in new user namespace")
nss = append(nss, specs.LinuxNamespace{Type: specs.UserNamespace})
+
+ if conf.TestOnlyAllowRunAsCurrentUser {
+ log.Warningf("Running sandbox in test mode as current user (uid=%d gid=%d). This is only safe in tests!", os.Getuid(), os.Getgid())
+ } else if specutils.CanSetUIDGID() {
+ // If we have CAP_SETUID and CAP_SETGID, then we can also run
+ // as user nobody.
+
+ // Map nobody in the new namespace to nobody in the parent namespace.
+ const nobody = 65534
+ cmd.SysProcAttr.UidMappings = []syscall.SysProcIDMap{{
+ ContainerID: int(nobody),
+ HostID: int(nobody),
+ Size: int(1),
+ }}
+ cmd.SysProcAttr.GidMappings = []syscall.SysProcIDMap{{
+ ContainerID: int(nobody),
+ HostID: int(nobody),
+ Size: int(1),
+ }}
+
+ // Set credentials to run as user and group nobody.
+ cmd.SysProcAttr.Credential = &syscall.Credential{
+ Uid: nobody,
+ Gid: nobody,
+ }
+ } else {
+ return fmt.Errorf("can't run sandbox process as user nobody since we don't have CAP_SETUID or CAP_SETGID")
+ }
}
// Log the fds we are donating to the sandbox process.
@@ -399,6 +427,7 @@ func (s *Sandbox) createSandboxProcess(spec *specs.Spec, conf *boot.Config, bund
}
log.Debugf("Starting sandbox: %s %v", binPath, cmd.Args)
+ log.Debugf("SysProcAttr: %+v", cmd.SysProcAttr)
if err := specutils.StartInNS(cmd, nss); err != nil {
return err
}
diff --git a/runsc/specutils/BUILD b/runsc/specutils/BUILD
index 97a504b20..e73b2293f 100644
--- a/runsc/specutils/BUILD
+++ b/runsc/specutils/BUILD
@@ -18,6 +18,7 @@ go_library(
"//pkg/sentry/kernel/auth",
"@com_github_cenkalti_backoff//:go_default_library",
"@com_github_opencontainers_runtime-spec//specs-go:go_default_library",
+ "@com_github_syndtr_gocapability//capability:go_default_library",
"@org_golang_x_sys//unix:go_default_library",
],
)
diff --git a/runsc/specutils/namespace.go b/runsc/specutils/namespace.go
index 80eaad965..356943a65 100644
--- a/runsc/specutils/namespace.go
+++ b/runsc/specutils/namespace.go
@@ -23,6 +23,7 @@ import (
"syscall"
specs "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/syndtr/gocapability/capability"
"golang.org/x/sys/unix"
"gvisor.googlesource.com/gvisor/pkg/log"
)
@@ -202,3 +203,16 @@ func SetUIDGIDMappings(cmd *exec.Cmd, s *specs.Spec) {
})
}
}
+
+// CanSetUIDGID returns true if the user has SETUID and SETGID capabilities.
+func CanSetUIDGID() bool {
+ caps, err := capability.NewPid2(os.Getpid())
+ if err != nil {
+ return false
+ }
+ if err := caps.Load(); err != nil {
+ return false
+ }
+ return caps.Get(capability.EFFECTIVE, capability.CAP_SETUID) &&
+ caps.Get(capability.EFFECTIVE, capability.CAP_SETGID)
+}
diff --git a/runsc/test/testutil/testutil.go b/runsc/test/testutil/testutil.go
index 4429b981b..77bd56912 100644
--- a/runsc/test/testutil/testutil.go
+++ b/runsc/test/testutil/testutil.go
@@ -104,13 +104,14 @@ func FindFile(path string) (string, error) {
// TestConfig return the default configuration to use in tests.
func TestConfig() *boot.Config {
return &boot.Config{
- Debug: true,
- LogFormat: "text",
- LogPackets: true,
- Network: boot.NetworkNone,
- Strace: true,
- MultiContainer: true,
- FileAccess: boot.FileAccessProxyExclusive,
+ Debug: true,
+ LogFormat: "text",
+ LogPackets: true,
+ Network: boot.NetworkNone,
+ Strace: true,
+ MultiContainer: true,
+ FileAccess: boot.FileAccessProxyExclusive,
+ TestOnlyAllowRunAsCurrentUser: true,
}
}