diff --git a/checkpoint.go b/checkpoint.go index d00cb044b48..62fa0cb128d 100644 --- a/checkpoint.go +++ b/checkpoint.go @@ -11,7 +11,7 @@ import ( criu "github.com/checkpoint-restore/go-criu/v4/rpc" "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/userns" "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -48,7 +48,7 @@ checkpointed.`, return err } // XXX: Currently this is untested with rootless containers. - if os.Geteuid() != 0 || system.RunningInUserNS() { + if os.Geteuid() != 0 || userns.RunningInUserNS() { logrus.Warn("runc checkpoint is untested with rootless containers") } diff --git a/libcontainer/cgroups/fs/devices.go b/libcontainer/cgroups/fs/devices.go index 9a37e68ec65..a098e3b793e 100644 --- a/libcontainer/cgroups/fs/devices.go +++ b/libcontainer/cgroups/fs/devices.go @@ -12,7 +12,7 @@ import ( "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/devices" - "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/userns" ) type DevicesGroup struct { @@ -55,7 +55,7 @@ func buildEmulator(rules []*devices.Rule) (*cgroupdevices.Emulator, error) { } func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error { - if system.RunningInUserNS() || cgroup.SkipDevices { + if userns.RunningInUserNS() || cgroup.SkipDevices { return nil } diff --git a/libcontainer/cgroups/fs2/devices.go b/libcontainer/cgroups/fs2/devices.go index 99559fec5b3..61c00a96d6c 100644 --- a/libcontainer/cgroups/fs2/devices.go +++ b/libcontainer/cgroups/fs2/devices.go @@ -7,7 +7,7 @@ import ( "github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/devices" - "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/userns" "github.com/pkg/errors" "golang.org/x/sys/unix" @@ -36,7 +36,7 @@ func canSkipEBPFError(cgroup *configs.Cgroup) bool { // have the necessary privileges to mknod(2) device inodes or access // host-level instances (though ideally we would be blocking device access // for rootless containers anyway). - if system.RunningInUserNS() { + if userns.RunningInUserNS() { return true } diff --git a/libcontainer/cgroups/systemd/user.go b/libcontainer/cgroups/systemd/user.go index 8fe91688477..450a2469402 100644 --- a/libcontainer/cgroups/systemd/user.go +++ b/libcontainer/cgroups/systemd/user.go @@ -13,7 +13,7 @@ import ( systemdDbus "github.com/coreos/go-systemd/v22/dbus" dbus "github.com/godbus/dbus/v5" - "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/userns" "github.com/pkg/errors" ) @@ -52,7 +52,7 @@ func NewUserSystemdDbus() (*systemdDbus.Conn, error) { // // Otherwise returns os.Getuid() . func DetectUID() (int, error) { - if !system.RunningInUserNS() { + if !userns.RunningInUserNS() { return os.Getuid(), nil } b, err := exec.Command("busctl", "--user", "--no-pager", "status").CombinedOutput() diff --git a/libcontainer/cgroups/utils.go b/libcontainer/cgroups/utils.go index a542b538eef..ce7c1163f6e 100644 --- a/libcontainer/cgroups/utils.go +++ b/libcontainer/cgroups/utils.go @@ -16,7 +16,7 @@ import ( "time" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" - "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/userns" "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) @@ -37,7 +37,7 @@ func IsCgroup2UnifiedMode() bool { var st unix.Statfs_t err := unix.Statfs(unifiedMountpoint, &st) if err != nil { - if os.IsNotExist(err) && system.RunningInUserNS() { + if os.IsNotExist(err) && userns.RunningInUserNS() { // ignore the "not found" error if running in userns logrus.WithError(err).Debugf("%s missing, assuming cgroup v1", unifiedMountpoint) isUnified = false diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index 411496ab7c6..ed38e77219b 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -19,7 +19,7 @@ import ( "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/devices" - "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/userns" "github.com/opencontainers/runc/libcontainer/utils" libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" "github.com/opencontainers/runtime-spec/specs-go" @@ -603,7 +603,7 @@ func reOpenDevNull() error { // Create the device nodes in the container. func createDevices(config *configs.Config) error { - useBindMount := system.RunningInUserNS() || config.Namespaces.Contains(configs.NEWUSER) + useBindMount := userns.RunningInUserNS() || config.Namespaces.Contains(configs.NEWUSER) oldMask := unix.Umask(0000) for _, node := range config.Devices { diff --git a/libcontainer/system/linux.go b/libcontainer/system/linux.go index 49471960be5..4379a207088 100644 --- a/libcontainer/system/linux.go +++ b/libcontainer/system/linux.go @@ -3,12 +3,9 @@ package system import ( - "os" "os/exec" - "sync" "unsafe" - "github.com/opencontainers/runc/libcontainer/user" "golang.org/x/sys/unix" ) @@ -87,52 +84,6 @@ func Setctty() error { return nil } -var ( - inUserNS bool - nsOnce sync.Once -) - -// RunningInUserNS detects whether we are currently running in a user namespace. -// Originally copied from github.com/lxc/lxd/shared/util.go -func RunningInUserNS() bool { - nsOnce.Do(func() { - uidmap, err := user.CurrentProcessUIDMap() - if err != nil { - // This kernel-provided file only exists if user namespaces are supported - return - } - inUserNS = UIDMapInUserNS(uidmap) - }) - return inUserNS -} - -func UIDMapInUserNS(uidmap []user.IDMap) bool { - /* - * We assume we are in the initial user namespace if we have a full - * range - 4294967295 uids starting at uid 0. - */ - if len(uidmap) == 1 && uidmap[0].ID == 0 && uidmap[0].ParentID == 0 && uidmap[0].Count == 4294967295 { - return false - } - return true -} - -// GetParentNSeuid returns the euid within the parent user namespace -func GetParentNSeuid() int64 { - euid := int64(os.Geteuid()) - uidmap, err := user.CurrentProcessUIDMap() - if err != nil { - // This kernel-provided file only exists if user namespaces are supported - return euid - } - for _, um := range uidmap { - if um.ID <= euid && euid <= um.ID+um.Count-1 { - return um.ParentID + euid - um.ID - } - } - return euid -} - // SetSubreaper sets the value i as the subreaper setting for the calling process func SetSubreaper(i int) error { return unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0) diff --git a/libcontainer/system/unsupported.go b/libcontainer/system/unsupported.go deleted file mode 100644 index b94be74a664..00000000000 --- a/libcontainer/system/unsupported.go +++ /dev/null @@ -1,27 +0,0 @@ -// +build !linux - -package system - -import ( - "os" - - "github.com/opencontainers/runc/libcontainer/user" -) - -// RunningInUserNS is a stub for non-Linux systems -// Always returns false -func RunningInUserNS() bool { - return false -} - -// UIDMapInUserNS is a stub for non-Linux systems -// Always returns false -func UIDMapInUserNS(uidmap []user.IDMap) bool { - return false -} - -// GetParentNSeuid returns the euid within the parent user namespace -// Always returns os.Geteuid on non-linux -func GetParentNSeuid() int { - return os.Geteuid() -} diff --git a/libcontainer/system/userns_deprecated.go b/libcontainer/system/userns_deprecated.go new file mode 100644 index 00000000000..84f6f8bb85b --- /dev/null +++ b/libcontainer/system/userns_deprecated.go @@ -0,0 +1,17 @@ +package system + +import "github.com/opencontainers/runc/libcontainer/userns" + +var ( + // RunningInUserNS detects whether we are currently running in a user namespace. + // Originally copied from github.com/lxc/lxd/shared/util.go + // Deprecated: use github.com/opencontainers/runc/libcontainer/userns.RunningInUserNS + RunningInUserNS = userns.RunningInUserNS + + // Deprecated: use github.com/opencontainers/runc/libcontainer/userns.UIDMapInUserNS + UIDMapInUserNS = userns.RunningInUserNS + + // GetParentNSeuid returns the euid within the parent user namespace + // Deprecated: use github.com/opencontainers/runc/libcontainer/userns.RunningInUserNS + GetParentNSeuid = userns.RunningInUserNS +) diff --git a/libcontainer/userns/userns.go b/libcontainer/userns/userns.go new file mode 100644 index 00000000000..4d89bb2f68a --- /dev/null +++ b/libcontainer/userns/userns.go @@ -0,0 +1,12 @@ +package userns + +var ( + // RunningInUserNS detects whether we are currently running in a user namespace. + // Originally copied from github.com/lxc/lxd/shared/util.go + RunningInUserNS = runningInUserNS + + UIDMapInUserNS = uidMapInUserNS + + // GetParentNSeuid returns the euid within the parent user namespace + GetParentNSeuid = getParentNSeuid +) diff --git a/libcontainer/system/system_fuzzer.go b/libcontainer/userns/userns_fuzzer.go similarity index 82% rename from libcontainer/system/system_fuzzer.go rename to libcontainer/userns/userns_fuzzer.go index c1d7630fefa..529f8eaea2f 100644 --- a/libcontainer/system/system_fuzzer.go +++ b/libcontainer/userns/userns_fuzzer.go @@ -1,6 +1,6 @@ // +build gofuzz -package system +package userns import ( "strings" @@ -10,6 +10,6 @@ import ( func FuzzUIDMap(data []byte) int { uidmap, _ := user.ParseIDMap(strings.NewReader(string(data))) - _ = UIDMapInUserNS(uidmap) + _ = uidMapInUserNS(uidmap) return 1 } diff --git a/libcontainer/userns/userns_linux.go b/libcontainer/userns/userns_linux.go new file mode 100644 index 00000000000..3cc076baa52 --- /dev/null +++ b/libcontainer/userns/userns_linux.go @@ -0,0 +1,54 @@ +package userns + +import ( + "os" + "sync" + + "github.com/opencontainers/runc/libcontainer/user" +) + +var ( + inUserNS bool + nsOnce sync.Once +) + +// runningInUserNS detects whether we are currently running in a user namespace. +// Originally copied from github.com/lxc/lxd/shared/util.go +func runningInUserNS() bool { + nsOnce.Do(func() { + uidmap, err := user.CurrentProcessUIDMap() + if err != nil { + // This kernel-provided file only exists if user namespaces are supported + return + } + inUserNS = uidMapInUserNS(uidmap) + }) + return inUserNS +} + +func uidMapInUserNS(uidmap []user.IDMap) bool { + /* + * We assume we are in the initial user namespace if we have a full + * range - 4294967295 uids starting at uid 0. + */ + if len(uidmap) == 1 && uidmap[0].ID == 0 && uidmap[0].ParentID == 0 && uidmap[0].Count == 4294967295 { + return false + } + return true +} + +// getParentNSeuid returns the euid within the parent user namespace +func getParentNSeuid() int64 { + euid := int64(os.Geteuid()) + uidmap, err := user.CurrentProcessUIDMap() + if err != nil { + // This kernel-provided file only exists if user namespaces are supported + return euid + } + for _, um := range uidmap { + if um.ID <= euid && euid <= um.ID+um.Count-1 { + return um.ParentID + euid - um.ID + } + } + return euid +} diff --git a/libcontainer/system/linux_test.go b/libcontainer/userns/userns_linux_test.go similarity index 98% rename from libcontainer/system/linux_test.go rename to libcontainer/userns/userns_linux_test.go index 4d613d8473d..e4a49ecde32 100644 --- a/libcontainer/system/linux_test.go +++ b/libcontainer/userns/userns_linux_test.go @@ -1,6 +1,6 @@ // +build linux -package system +package userns import ( "strings" diff --git a/libcontainer/userns/userns_unsupported.go b/libcontainer/userns/userns_unsupported.go new file mode 100644 index 00000000000..dcbc7a10859 --- /dev/null +++ b/libcontainer/userns/userns_unsupported.go @@ -0,0 +1,27 @@ +// +build !linux + +package userns + +import ( + "os" + + "github.com/opencontainers/runc/libcontainer/user" +) + +// runningInUserNS is a stub for non-Linux systems +// Always returns false +func runningInUserNS() bool { + return false +} + +// uidMapInUserNS is a stub for non-Linux systems +// Always returns false +func uidMapInUserNS(uidmap []user.IDMap) bool { + return false +} + +// getParentNSeuid returns the euid within the parent user namespace +// Always returns os.Geteuid on non-linux +func getParentNSeuid() int { + return os.Geteuid() +} diff --git a/restore.go b/restore.go index ec7308221f0..ed69d15e784 100644 --- a/restore.go +++ b/restore.go @@ -6,7 +6,7 @@ import ( "os" "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/userns" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -97,7 +97,7 @@ using the runc checkpoint command.`, return err } // XXX: Currently this is untested with rootless containers. - if os.Geteuid() != 0 || system.RunningInUserNS() { + if os.Geteuid() != 0 || userns.RunningInUserNS() { logrus.Warn("runc checkpoint is untested with rootless containers") } diff --git a/rootless_linux.go b/rootless_linux.go index 348f7c4ffca..3c21053846b 100644 --- a/rootless_linux.go +++ b/rootless_linux.go @@ -6,7 +6,7 @@ import ( "os" "github.com/opencontainers/runc/libcontainer/cgroups/systemd" - "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/userns" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -25,7 +25,7 @@ func shouldUseRootlessCgroupManager(context *cli.Context) (bool, error) { if os.Geteuid() != 0 { return true, nil } - if !system.RunningInUserNS() { + if !userns.RunningInUserNS() { // euid == 0 , in the initial ns (i.e. the real root) return false, nil } @@ -60,7 +60,7 @@ func shouldHonorXDGRuntimeDir() bool { if os.Geteuid() != 0 { return true } - if !system.RunningInUserNS() { + if !userns.RunningInUserNS() { // euid == 0 , in the initial ns (i.e. the real root) // in this case, we should use /run/runc and ignore // $XDG_RUNTIME_DIR (e.g. /run/user/0) for backward