mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
committed by
Shentubot
parent
6779bd1187
commit
cf226d48ce
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user