Switch to root in userns when CAP_SYS_CHROOT is also missing

Some tests check current capabilities and re-run the tests as root inside
userns if required capabibilities are missing. It was checking for
CAP_SYS_ADMIN only, CAP_SYS_CHROOT is also required now.

PiperOrigin-RevId: 214949226
Change-Id: Ic81363969fa76c04da408fae8ea7520653266312
This commit is contained in:
Fabricio Voznika
2018-09-28 09:44:13 -07:00
committed by Shentubot
parent 6779bd1187
commit cf226d48ce
7 changed files with 24 additions and 25 deletions
+5 -1
View File
@@ -60,7 +60,11 @@ func applyCaps(caps *specs.LinuxCapabilities) error {
newCaps.Set(c, set...)
}
return newCaps.Apply(capability.CAPS | capability.BOUNDS | capability.AMBS)
if err := newCaps.Apply(capability.CAPS | capability.BOUNDS | capability.AMBS); err != nil {
return err
}
log.Infof("Capabilities applied: %+v", newCaps)
return nil
}
func getCaps(which capability.CapType, caps *specs.LinuxCapabilities) []string {
-1
View File
@@ -85,7 +85,6 @@ func setCapsAndCallSelf(args []string, caps *specs.LinuxCapabilities) error {
return err
}
log.Infof("Capabilities applied: %+v", caps)
log.Infof("Execve %q again, bye!", binPath)
syscall.Exec(binPath, args, []string{})
panic("unreachable")
+1
View File
@@ -25,6 +25,7 @@ go_library(
"//runsc/specutils",
"@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",
"@com_github_vishvananda_netlink//:go_default_library",
],
)
+4 -3
View File
@@ -26,6 +26,7 @@ import (
"github.com/cenkalti/backoff"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/syndtr/gocapability/capability"
"gvisor.googlesource.com/gvisor/pkg/control/client"
"gvisor.googlesource.com/gvisor/pkg/control/server"
"gvisor.googlesource.com/gvisor/pkg/log"
@@ -415,7 +416,7 @@ func (s *Sandbox) createSandboxProcess(spec *specs.Spec, conf *boot.Config, bund
// as user nobody.
if conf.TestOnlyAllowRunAsCurrentUserWithoutChroot {
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() {
} else if specutils.HasCapabilities(capability.CAP_SETUID, capability.CAP_SETGID) {
// Map nobody in the new namespace to nobody in the parent namespace.
const nobody = 65534
cmd.SysProcAttr.UidMappings = []syscall.SysProcIDMap{{
@@ -442,7 +443,7 @@ func (s *Sandbox) createSandboxProcess(spec *specs.Spec, conf *boot.Config, bund
// bind-mount the executable inside it.
if conf.TestOnlyAllowRunAsCurrentUserWithoutChroot {
log.Warningf("Running sandbox in test mode without chroot. This is only safe in tests!")
} else if specutils.HasCapSysAdmin() {
} else if specutils.HasCapabilities(capability.CAP_SYS_ADMIN, capability.CAP_SYS_CHROOT) {
log.Infof("Sandbox will be started in minimal chroot")
chroot, err := setUpChroot()
if err != nil {
@@ -453,7 +454,7 @@ func (s *Sandbox) createSandboxProcess(spec *specs.Spec, conf *boot.Config, bund
cmd.Args[0] = "/runsc"
cmd.Path = "/runsc"
} else {
return fmt.Errorf("can't run sandbox process in minimal chroot since we don't have CAP_SYS_ADMIN")
return fmt.Errorf("can't run sandbox process in minimal chroot since we don't have CAP_SYS_ADMIN and CAP_SYS_CHROOT")
}
}
+7 -15
View File
@@ -204,8 +204,8 @@ func SetUIDGIDMappings(cmd *exec.Cmd, s *specs.Spec) {
}
}
// CanSetUIDGID returns true if the user has SETUID and SETGID capabilities.
func CanSetUIDGID() bool {
// HasCapabilities returns true if the user has all capabilties in 'cs'.
func HasCapabilities(cs ...capability.Cap) bool {
caps, err := capability.NewPid2(os.Getpid())
if err != nil {
return false
@@ -213,18 +213,10 @@ func CanSetUIDGID() bool {
if err := caps.Load(); err != nil {
return false
}
return caps.Get(capability.EFFECTIVE, capability.CAP_SETUID) &&
caps.Get(capability.EFFECTIVE, capability.CAP_SETGID)
}
// HasCapSysAdmin returns true if the user has CAP_SYS_ADMIN capability.
func HasCapSysAdmin() bool {
caps, err := capability.NewPid2(os.Getpid())
if err != nil {
return false
for _, c := range cs {
if !caps.Get(capability.EFFECTIVE, c) {
return false
}
}
if err := caps.Load(); err != nil {
return false
}
return caps.Get(capability.EFFECTIVE, capability.CAP_SYS_ADMIN)
return true
}
+1
View File
@@ -18,5 +18,6 @@ go_library(
"//runsc/specutils",
"@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",
],
)
+6 -5
View File
@@ -32,6 +32,7 @@ import (
"github.com/cenkalti/backoff"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/syndtr/gocapability/capability"
"gvisor.googlesource.com/gvisor/runsc/boot"
"gvisor.googlesource.com/gvisor/runsc/specutils"
)
@@ -234,12 +235,12 @@ func WaitForHTTP(port int, timeout time.Duration) error {
return Poll(cb, timeout)
}
// RunAsRoot ensures the test runs with CAP_SYS_ADMIN. If need it will create
// a new user namespace and reexecute the test as root inside of the namespace.
// This functionr returns when it's running as root. If it needs to create
// another process, it will exit from there and not return.
// RunAsRoot ensures the test runs with CAP_SYS_ADMIN and CAP_SYS_CHROOT. If
// need it will create a new user namespace and reexecute the test as root
// inside of the namespace. This functionr returns when it's running as root. If
// it needs to create another process, it will exit from there and not return.
func RunAsRoot() {
if specutils.HasCapSysAdmin() {
if specutils.HasCapabilities(capability.CAP_SYS_ADMIN, capability.CAP_SYS_CHROOT) {
return
}