From 348e3c11c02c59b85ec48403849648bd446def4d Mon Sep 17 00:00:00 2001 From: Shelley-BaoYue Date: Mon, 28 Oct 2024 20:18:30 +0800 Subject: [PATCH] revert runc version upgraded Signed-off-by: Shelley-BaoYue --- go.mod | 4 +- go.sum | 7 +- .../runc/libcontainer/cgroups/file.go | 31 ++- .../runc/libcontainer/cgroups/fs/cpu.go | 20 +- .../runc/libcontainer/cgroups/fs/memory.go | 4 - .../runc/libcontainer/cgroups/fs/paths.go | 1 - .../runc/libcontainer/cgroups/fs2/memory.go | 18 +- .../runc/libcontainer/cgroups/stats.go | 2 - .../runc/libcontainer/configs/config.go | 6 +- .../runc/libcontainer/configs/config_linux.go | 30 +-- .../libcontainer/configs/validate/rootless.go | 31 +-- .../configs/validate/validator.go | 12 +- .../runc/libcontainer/container_linux.go | 11 +- .../runc/libcontainer/init_linux.go | 50 +---- .../runc/libcontainer/process_linux.go | 18 +- .../runc/libcontainer/rootfs_linux.go | 1 - .../runc/libcontainer/setns_init_linux.go | 46 +---- .../runc/libcontainer/standard_init_linux.go | 22 +-- .../runc/libcontainer/system/linux.go | 2 +- .../runc/libcontainer/system/rlimit_linux.go | 15 -- .../libcontainer/system/rlimit_linux_go122.go | 27 --- .../runc/libcontainer/system/rlimit_stub.go | 7 - .../runc/libcontainer/user/user.go | 1 + .../runc/libcontainer/userns/userns_maps.c | 79 -------- .../libcontainer/userns/userns_maps_linux.go | 186 ------------------ .../runc/libcontainer/utils/utils_unix.go | 64 +----- vendor/modules.txt | 6 +- 27 files changed, 79 insertions(+), 622 deletions(-) delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux_go122.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_stub.go delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps.c delete mode 100644 vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps_linux.go diff --git a/go.mod b/go.mod index 7ccd340c9d7..53a0eac219d 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.2 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 - golang.org/x/net v0.24.0 + golang.org/x/net v0.23.0 golang.org/x/time v0.5.0 google.golang.org/grpc v1.63.0 google.golang.org/protobuf v1.33.0 @@ -204,7 +204,7 @@ require ( github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect - github.com/opencontainers/runc v1.1.13 // indirect + github.com/opencontainers/runc v1.1.10 // indirect github.com/opencontainers/runtime-spec v1.0.3-0.20220909204839-494a5a6aca78 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index c1c35d46879..9327cf2c826 100644 --- a/go.sum +++ b/go.sum @@ -1656,8 +1656,8 @@ github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= -github.com/opencontainers/runc v1.1.13 h1:98S2srgG9vw0zWcDpFMn5TRrh8kLxa/5OFUstuUhmRs= -github.com/opencontainers/runc v1.1.13/go.mod h1:R016aXacfp/gwQBYw2FDGa9m+n6atbLWrYY8hNMT/sA= +github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40= +github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -2153,9 +2153,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go index f6e1b73bd92..48b263a1661 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/file.go @@ -77,16 +77,16 @@ var ( // TestMode is set to true by unit tests that need "fake" cgroupfs. TestMode bool - cgroupRootHandle *os.File - prepOnce sync.Once - prepErr error - resolveFlags uint64 + cgroupFd int = -1 + prepOnce sync.Once + prepErr error + resolveFlags uint64 ) func prepareOpenat2() error { prepOnce.Do(func() { fd, err := unix.Openat2(-1, cgroupfsDir, &unix.OpenHow{ - Flags: unix.O_DIRECTORY | unix.O_PATH | unix.O_CLOEXEC, + Flags: unix.O_DIRECTORY | unix.O_PATH, }) if err != nil { prepErr = &os.PathError{Op: "openat2", Path: cgroupfsDir, Err: err} @@ -97,16 +97,15 @@ func prepareOpenat2() error { } return } - file := os.NewFile(uintptr(fd), cgroupfsDir) - var st unix.Statfs_t - if err := unix.Fstatfs(int(file.Fd()), &st); err != nil { + if err = unix.Fstatfs(fd, &st); err != nil { prepErr = &os.PathError{Op: "statfs", Path: cgroupfsDir, Err: err} logrus.Warnf("falling back to securejoin: %s", prepErr) return } - cgroupRootHandle = file + cgroupFd = fd + resolveFlags = unix.RESOLVE_BENEATH | unix.RESOLVE_NO_MAGICLINKS if st.Type == unix.CGROUP2_SUPER_MAGIC { // cgroupv2 has a single mountpoint and no "cpu,cpuacct" symlinks @@ -133,7 +132,7 @@ func openFile(dir, file string, flags int) (*os.File, error) { return openFallback(path, flags, mode) } - fd, err := unix.Openat2(int(cgroupRootHandle.Fd()), relPath, + fd, err := unix.Openat2(cgroupFd, relPath, &unix.OpenHow{ Resolve: resolveFlags, Flags: uint64(flags) | unix.O_CLOEXEC, @@ -141,20 +140,20 @@ func openFile(dir, file string, flags int) (*os.File, error) { }) if err != nil { err = &os.PathError{Op: "openat2", Path: path, Err: err} - // Check if cgroupRootHandle is still opened to cgroupfsDir + // Check if cgroupFd is still opened to cgroupfsDir // (happens when this package is incorrectly used // across the chroot/pivot_root/mntns boundary, or // when /sys/fs/cgroup is remounted). // // TODO: if such usage will ever be common, amend this - // to reopen cgroupRootHandle and retry openat2. - fdStr := strconv.Itoa(int(cgroupRootHandle.Fd())) + // to reopen cgroupFd and retry openat2. + fdStr := strconv.Itoa(cgroupFd) fdDest, _ := os.Readlink("/proc/self/fd/" + fdStr) if fdDest != cgroupfsDir { - // Wrap the error so it is clear that cgroupRootHandle + // Wrap the error so it is clear that cgroupFd // is opened to an unexpected/wrong directory. - err = fmt.Errorf("cgroupRootHandle %d unexpectedly opened to %s != %s: %w", - cgroupRootHandle.Fd(), fdDest, cgroupfsDir, err) + err = fmt.Errorf("cgroupFd %s unexpectedly opened to %s != %s: %w", + fdStr, fdDest, cgroupfsDir, err) } return nil, err } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go index 72c9cd70b50..6c79f899b48 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go @@ -35,31 +35,15 @@ func (s *CpuGroup) Apply(path string, r *configs.Resources, pid int) error { } func (s *CpuGroup) SetRtSched(path string, r *configs.Resources) error { - var period string if r.CpuRtPeriod != 0 { - period = strconv.FormatUint(r.CpuRtPeriod, 10) - if err := cgroups.WriteFile(path, "cpu.rt_period_us", period); err != nil { - // The values of cpu.rt_period_us and cpu.rt_runtime_us - // are inter-dependent and need to be set in a proper order. - // If the kernel rejects the new period value with EINVAL - // and the new runtime value is also being set, let's - // ignore the error for now and retry later. - if !errors.Is(err, unix.EINVAL) || r.CpuRtRuntime == 0 { - return err - } - } else { - period = "" + if err := cgroups.WriteFile(path, "cpu.rt_period_us", strconv.FormatUint(r.CpuRtPeriod, 10)); err != nil { + return err } } if r.CpuRtRuntime != 0 { if err := cgroups.WriteFile(path, "cpu.rt_runtime_us", strconv.FormatInt(r.CpuRtRuntime, 10)); err != nil { return err } - if period != "" { - if err := cgroups.WriteFile(path, "cpu.rt_period_us", period); err != nil { - return err - } - } } return nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go index 783566d68f0..a0e78074980 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go @@ -170,10 +170,6 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error { return err } stats.MemoryStats.SwapUsage = swapUsage - stats.MemoryStats.SwapOnlyUsage = cgroups.MemoryData{ - Usage: swapUsage.Usage - memoryUsage.Usage, - Failcnt: swapUsage.Failcnt - memoryUsage.Failcnt, - } kernelUsage, err := getMemoryData(path, "kmem") if err != nil { return err diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/paths.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/paths.go index 2cb970a3d55..1092331b25d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/paths.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/paths.go @@ -83,7 +83,6 @@ func tryDefaultCgroupRoot() string { if err != nil { return "" } - defer dir.Close() names, err := dir.Readdirnames(1) if err != nil { return "" diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go index 01fe7d8e12d..9cca98c4c0a 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go @@ -100,7 +100,7 @@ func statMemory(dirPath string, stats *cgroups.Stats) error { memoryUsage, err := getMemoryDataV2(dirPath, "") if err != nil { if errors.Is(err, unix.ENOENT) && dirPath == UnifiedMountpoint { - // The root cgroup does not have memory.{current,max,peak} + // The root cgroup does not have memory.{current,max} // so emulate those using data from /proc/meminfo and // /sys/fs/cgroup/memory.stat return rootStatsFromMeminfo(stats) @@ -108,12 +108,10 @@ func statMemory(dirPath string, stats *cgroups.Stats) error { return err } stats.MemoryStats.Usage = memoryUsage - swapOnlyUsage, err := getMemoryDataV2(dirPath, "swap") + swapUsage, err := getMemoryDataV2(dirPath, "swap") if err != nil { return err } - stats.MemoryStats.SwapOnlyUsage = swapOnlyUsage - swapUsage := swapOnlyUsage // As cgroup v1 reports SwapUsage values as mem+swap combined, // while in cgroup v2 swap values do not include memory, // report combined mem+swap for v1 compatibility. @@ -121,9 +119,6 @@ func statMemory(dirPath string, stats *cgroups.Stats) error { if swapUsage.Limit != math.MaxUint64 { swapUsage.Limit += memoryUsage.Limit } - // The `MaxUsage` of mem+swap cannot simply combine mem with - // swap. So set it to 0 for v1 compatibility. - swapUsage.MaxUsage = 0 stats.MemoryStats.SwapUsage = swapUsage return nil @@ -138,7 +133,6 @@ func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) { } usage := moduleName + ".current" limit := moduleName + ".max" - maxUsage := moduleName + ".peak" value, err := fscommon.GetCgroupParamUint(path, usage) if err != nil { @@ -158,14 +152,6 @@ func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) { } memoryData.Limit = value - // `memory.peak` since kernel 5.19 - // `memory.swap.peak` since kernel 6.5 - value, err = fscommon.GetCgroupParamUint(path, maxUsage) - if err != nil && !os.IsNotExist(err) { - return cgroups.MemoryData{}, err - } - memoryData.MaxUsage = value - return memoryData, nil } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go index 0d8371b05f1..40a81dd5a86 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go @@ -78,8 +78,6 @@ type MemoryStats struct { Usage MemoryData `json:"usage,omitempty"` // usage of memory + swap SwapUsage MemoryData `json:"swap_usage,omitempty"` - // usage of swap only - SwapOnlyUsage MemoryData `json:"swap_only_usage,omitempty"` // usage of kernel memory KernelUsage MemoryData `json:"kernel_usage,omitempty"` // usage of kernel TCP memory diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go index 6ebf5ec7b60..c1b4a0041c2 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go @@ -21,9 +21,9 @@ type Rlimit struct { // IDMap represents UID/GID Mappings for User Namespaces. type IDMap struct { - ContainerID int64 `json:"container_id"` - HostID int64 `json:"host_id"` - Size int64 `json:"size"` + ContainerID int `json:"container_id"` + HostID int `json:"host_id"` + Size int `json:"size"` } // Seccomp represents syscall restrictions diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go index 51fe940748a..8c02848b70a 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go @@ -1,10 +1,6 @@ package configs -import ( - "errors" - "fmt" - "math" -) +import "errors" var ( errNoUIDMap = errors.New("User namespaces enabled, but no uid mappings found.") @@ -20,18 +16,11 @@ func (c Config) HostUID(containerId int) (int, error) { if c.UidMappings == nil { return -1, errNoUIDMap } - id, found := c.hostIDFromMapping(int64(containerId), c.UidMappings) + id, found := c.hostIDFromMapping(containerId, c.UidMappings) if !found { return -1, errNoUserMap } - // If we are a 32-bit binary running on a 64-bit system, it's possible - // the mapped user is too large to store in an int, which means we - // cannot do the mapping. We can't just return an int64, because - // os.Setuid() takes an int. - if id > math.MaxInt { - return -1, fmt.Errorf("mapping for uid %d (host id %d) is larger than native integer size (%d)", containerId, id, math.MaxInt) - } - return int(id), nil + return id, nil } // Return unchanged id. return containerId, nil @@ -50,18 +39,11 @@ func (c Config) HostGID(containerId int) (int, error) { if c.GidMappings == nil { return -1, errNoGIDMap } - id, found := c.hostIDFromMapping(int64(containerId), c.GidMappings) + id, found := c.hostIDFromMapping(containerId, c.GidMappings) if !found { return -1, errNoGroupMap } - // If we are a 32-bit binary running on a 64-bit system, it's possible - // the mapped user is too large to store in an int, which means we - // cannot do the mapping. We can't just return an int64, because - // os.Setgid() takes an int. - if id > math.MaxInt { - return -1, fmt.Errorf("mapping for gid %d (host id %d) is larger than native integer size (%d)", containerId, id, math.MaxInt) - } - return int(id), nil + return id, nil } // Return unchanged id. return containerId, nil @@ -75,7 +57,7 @@ func (c Config) HostRootGID() (int, error) { // Utility function that gets a host ID for a container ID from user namespace map // if that ID is present in the map. -func (c Config) hostIDFromMapping(containerID int64, uMap []IDMap) (int64, bool) { +func (c Config) hostIDFromMapping(containerID int, uMap []IDMap) (int, bool) { for _, m := range uMap { if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) { hostID := m.HostID + (containerID - m.ContainerID) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go index 37c383366fe..9a6e5eb32a3 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go @@ -28,18 +28,25 @@ func (v *ConfigValidator) rootlessEUID(config *configs.Config) error { return nil } +func hasIDMapping(id int, mappings []configs.IDMap) bool { + for _, m := range mappings { + if id >= m.ContainerID && id < m.ContainerID+m.Size { + return true + } + } + return false +} + func rootlessEUIDMappings(config *configs.Config) error { if !config.Namespaces.Contains(configs.NEWUSER) { return errors.New("rootless container requires user namespaces") } - // We only require mappings if we are not joining another userns. - if path := config.Namespaces.PathOf(configs.NEWUSER); path == "" { - if len(config.UidMappings) == 0 { - return errors.New("rootless containers requires at least one UID mapping") - } - if len(config.GidMappings) == 0 { - return errors.New("rootless containers requires at least one GID mapping") - } + + if len(config.UidMappings) == 0 { + return errors.New("rootless containers requires at least one UID mapping") + } + if len(config.GidMappings) == 0 { + return errors.New("rootless containers requires at least one GID mapping") } return nil } @@ -63,8 +70,8 @@ func rootlessEUIDMount(config *configs.Config) error { // Ignore unknown mount options. continue } - if _, err := config.HostUID(uid); err != nil { - return fmt.Errorf("cannot specify uid=%d mount option for rootless container: %w", uid, err) + if !hasIDMapping(uid, config.UidMappings) { + return errors.New("cannot specify uid= mount options for unmapped uid in rootless containers") } } @@ -75,8 +82,8 @@ func rootlessEUIDMount(config *configs.Config) error { // Ignore unknown mount options. continue } - if _, err := config.HostGID(gid); err != nil { - return fmt.Errorf("cannot specify gid=%d mount option for rootless container: %w", gid, err) + if !hasIDMapping(gid, config.GidMappings) { + return errors.New("cannot specify gid= mount options for unmapped gid in rootless containers") } } } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go index ece70a45d31..4fbd308dadd 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go @@ -109,19 +109,11 @@ func (v *ConfigValidator) security(config *configs.Config) error { func (v *ConfigValidator) usernamespace(config *configs.Config) error { if config.Namespaces.Contains(configs.NEWUSER) { if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { - return errors.New("user namespaces aren't enabled in the kernel") + return errors.New("USER namespaces aren't enabled in the kernel") } - hasPath := config.Namespaces.PathOf(configs.NEWUSER) != "" - hasMappings := config.UidMappings != nil || config.GidMappings != nil - if !hasPath && !hasMappings { - return errors.New("user namespaces enabled, but no namespace path to join nor mappings to apply specified") - } - // The hasPath && hasMappings validation case is handled in specconv -- - // we cache the mappings in Config during specconv in the hasPath case, - // so we cannot do that validation here. } else { if config.UidMappings != nil || config.GidMappings != nil { - return errors.New("user namespace mappings specified, but user namespace isn't enabled in the config") + return errors.New("User namespace mappings specified, but USER namespace isn't enabled in the config") } } return nil diff --git a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go index 40b332f9810..2f17e37d43d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go @@ -353,15 +353,6 @@ func (c *linuxContainer) start(process *Process) (retErr error) { }() } - // Before starting "runc init", mark all non-stdio open files as O_CLOEXEC - // to make sure we don't leak any files into "runc init". Any files to be - // passed to "runc init" through ExtraFiles will get dup2'd by the Go - // runtime and thus their O_CLOEXEC flag will be cleared. This is some - // additional protection against attacks like CVE-2024-21626, by making - // sure we never leak files to "runc init" we didn't intend to. - if err := utils.CloseExecFrom(3); err != nil { - return fmt.Errorf("unable to mark non-stdio fds as cloexec: %w", err) - } if err := parent.start(); err != nil { return fmt.Errorf("unable to start container process: %w", err) } @@ -2277,7 +2268,7 @@ func ignoreTerminateErrors(err error) error { func requiresRootOrMappingTool(c *configs.Config) bool { gidMap := []configs.IDMap{ - {ContainerID: 0, HostID: int64(os.Getegid()), Size: 1}, + {ContainerID: 0, HostID: os.Getegid(), Size: 1}, } return !reflect.DeepEqual(c.GidMappings, gidMap) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go index c849ec6b797..5b88c71fc83 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go @@ -8,9 +8,7 @@ import ( "io" "net" "os" - "path/filepath" "strings" - "syscall" "unsafe" "github.com/containerd/console" @@ -85,11 +83,6 @@ func newContainerInit(t initType, pipe *os.File, consoleSocket *os.File, fifoFd, if err := populateProcessEnvironment(config.Env); err != nil { return nil, err } - - // Clean the RLIMIT_NOFILE cache in go runtime. - // Issue: https://github.com/opencontainers/runc/issues/4195 - maybeClearRlimitNofileCache(config.Rlimits) - switch t { case initSetns: // mountFds must be nil in this case. We don't mount while doing runc exec. @@ -142,32 +135,6 @@ func populateProcessEnvironment(env []string) error { return nil } -// verifyCwd ensures that the current directory is actually inside the mount -// namespace root of the current process. -func verifyCwd() error { - // getcwd(2) on Linux detects if cwd is outside of the rootfs of the - // current mount namespace root, and in that case prefixes "(unreachable)" - // to the returned string. glibc's getcwd(3) and Go's Getwd() both detect - // when this happens and return ENOENT rather than returning a non-absolute - // path. In both cases we can therefore easily detect if we have an invalid - // cwd by checking the return value of getcwd(3). See getcwd(3) for more - // details, and CVE-2024-21626 for the security issue that motivated this - // check. - // - // We have to use unix.Getwd() here because os.Getwd() has a workaround for - // $PWD which involves doing stat(.), which can fail if the current - // directory is inaccessible to the container process. - if wd, err := unix.Getwd(); errors.Is(err, unix.ENOENT) { - return errors.New("current working directory is outside of container mount namespace root -- possible container breakout detected") - } else if err != nil { - return fmt.Errorf("failed to verify if current working directory is safe: %w", err) - } else if !filepath.IsAbs(wd) { - // We shouldn't ever hit this, but check just in case. - return fmt.Errorf("current working directory is not absolute -- possible container breakout detected: cwd is %q", wd) - } - return nil -} - // finalizeNamespace drops the caps, sets the correct user // and working dir, and closes any leaked file descriptors // before executing the command inside the namespace @@ -226,10 +193,6 @@ func finalizeNamespace(config *initConfig) error { return fmt.Errorf("chdir to cwd (%q) set in config.json failed: %w", config.Cwd, err) } } - // Make sure our final working directory is inside the container. - if err := verifyCwd(); err != nil { - return err - } if err := system.ClearKeepCaps(); err != nil { return fmt.Errorf("unable to clear keep caps: %w", err) } @@ -267,6 +230,7 @@ func setupConsole(socket *os.File, config *initConfig, mount bool) error { Height: config.ConsoleHeight, Width: config.ConsoleWidth, }) + if err != nil { return err } @@ -523,18 +487,6 @@ func setupRoute(config *configs.Config) error { return nil } -func maybeClearRlimitNofileCache(limits []configs.Rlimit) { - for _, rlimit := range limits { - if rlimit.Type == syscall.RLIMIT_NOFILE { - system.ClearRlimitNofileCache(&syscall.Rlimit{ - Cur: rlimit.Soft, - Max: rlimit.Hard, - }) - return - } - } -} - func setupRlimits(limits []configs.Rlimit, pid int) error { for _, rlimit := range limits { if err := unix.Prlimit(pid, rlimit.Type, &unix.Rlimit{Max: rlimit.Hard, Cur: rlimit.Soft}, nil); err != nil { diff --git a/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go index ac3b104ea02..0d9ceb9c98c 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go @@ -152,7 +152,11 @@ func (p *setnsProcess) start() (retErr error) { } } } - + // set rlimits, this has to be done here because we lose permissions + // to raise the limits once we enter a user-namespace + if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil { + return fmt.Errorf("error setting rlimits for process: %w", err) + } if err := utils.WriteJSON(p.messageSockPair.parent, p.config); err != nil { return fmt.Errorf("error writing config to pipe: %w", err) } @@ -160,14 +164,8 @@ func (p *setnsProcess) start() (retErr error) { ierr := parseSync(p.messageSockPair.parent, func(sync *syncT) error { switch sync.Type { case procReady: - // Set rlimits, this has to be done here because we lose permissions - // to raise the limits once we enter a user-namespace - if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil { - return fmt.Errorf("error setting rlimits for ready process: %w", err) - } - - // Sync with child. - return writeSync(p.messageSockPair.parent, procRun) + // This shouldn't happen. + panic("unexpected procReady in setns") case procHooks: // This shouldn't happen. panic("unexpected procHooks in setns") @@ -497,7 +495,7 @@ func (p *initProcess) start() (retErr error) { return err } case procReady: - // Set rlimits, this has to be done here because we lose permissions + // set rlimits, this has to be done here because we lose permissions // to raise the limits once we enter a user-namespace if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil { return fmt.Errorf("error setting rlimits for ready process: %w", err) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go index 52ad3ba121f..c701d6a2fcd 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go @@ -602,7 +602,6 @@ func checkProcMount(rootfs, dest, source string) error { "/proc/slabinfo", "/proc/net/dev", "/proc/sys/kernel/ns_last_pid", - "/proc/sys/crypto/fips_enabled", } for _, valid := range validProcMounts { path, err := filepath.Rel(filepath.Join(rootfs, valid), dest) diff --git a/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go index bb358901c34..09ab552b3d1 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "os" - "os/exec" "strconv" "github.com/opencontainers/selinux/go-selinux" @@ -15,7 +14,6 @@ import ( "github.com/opencontainers/runc/libcontainer/keys" "github.com/opencontainers/runc/libcontainer/seccomp" "github.com/opencontainers/runc/libcontainer/system" - "github.com/opencontainers/runc/libcontainer/utils" ) // linuxSetnsInit performs the container's initialization for running a new process @@ -48,7 +46,6 @@ func (l *linuxSetnsInit) Init() error { } } } - if l.config.CreateConsole { if err := setupConsole(l.consoleSocket, l.config, false); err != nil { return err @@ -62,14 +59,6 @@ func (l *linuxSetnsInit) Init() error { return err } } - - // Tell our parent that we're ready to exec. This must be done before the - // Seccomp rules have been applied, because we need to be able to read and - // write to a socket. - if err := syncParentReady(l.pipe); err != nil { - return fmt.Errorf("sync ready: %w", err) - } - if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil { return err } @@ -93,21 +82,6 @@ func (l *linuxSetnsInit) Init() error { if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { return err } - - // Check for the arg before waiting to make sure it exists and it is - // returned as a create time error. - name, err := exec.LookPath(l.config.Args[0]) - if err != nil { - return err - } - // exec.LookPath in Go < 1.20 might return no error for an executable - // residing on a file system mounted with noexec flag, so perform this - // extra check now while we can still return a proper error. - // TODO: remove this once go < 1.20 is not supported. - if err := eaccess(name); err != nil { - return &os.PathError{Op: "eaccess", Path: name, Err: err} - } - // Set seccomp as close to execve as possible, so as few syscalls take // place afterward (reducing the amount of syscalls that users need to // enable in their seccomp profiles). @@ -127,23 +101,5 @@ func (l *linuxSetnsInit) Init() error { return &os.PathError{Op: "close log pipe", Path: "fd " + strconv.Itoa(l.logFd), Err: err} } - // Close all file descriptors we are not passing to the container. This is - // necessary because the execve target could use internal runc fds as the - // execve path, potentially giving access to binary files from the host - // (which can then be opened by container processes, leading to container - // escapes). Note that because this operation will close any open file - // descriptors that are referenced by (*os.File) handles from underneath - // the Go runtime, we must not do any file operations after this point - // (otherwise the (*os.File) finaliser could close the wrong file). See - // CVE-2024-21626 for more information as to why this protection is - // necessary. - // - // This is not needed for runc-dmz, because the extra execve(2) step means - // that all O_CLOEXEC file descriptors have already been closed and thus - // the second execve(2) from runc-dmz cannot access internal file - // descriptors from runc. - if err := utils.UnsafeCloseFrom(l.config.PassedFilesCount + 3); err != nil { - return err - } - return system.Exec(name, l.config.Args[0:], os.Environ()) + return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ()) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go index d9a6a224c5c..c09a7bed30e 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go @@ -17,7 +17,6 @@ import ( "github.com/opencontainers/runc/libcontainer/keys" "github.com/opencontainers/runc/libcontainer/seccomp" "github.com/opencontainers/runc/libcontainer/system" - "github.com/opencontainers/runc/libcontainer/utils" ) type linuxStandardInit struct { @@ -155,8 +154,7 @@ func (l *linuxStandardInit) Init() error { return &os.SyscallError{Syscall: "prctl(SET_NO_NEW_PRIVS)", Err: err} } } - - // Tell our parent that we're ready to exec. This must be done before the + // Tell our parent that we're ready to Execv. This must be done before the // Seccomp rules have been applied, because we need to be able to read and // write to a socket. if err := syncParentReady(l.pipe); err != nil { @@ -260,23 +258,5 @@ func (l *linuxStandardInit) Init() error { return err } - // Close all file descriptors we are not passing to the container. This is - // necessary because the execve target could use internal runc fds as the - // execve path, potentially giving access to binary files from the host - // (which can then be opened by container processes, leading to container - // escapes). Note that because this operation will close any open file - // descriptors that are referenced by (*os.File) handles from underneath - // the Go runtime, we must not do any file operations after this point - // (otherwise the (*os.File) finaliser could close the wrong file). See - // CVE-2024-21626 for more information as to why this protection is - // necessary. - // - // This is not needed for runc-dmz, because the extra execve(2) step means - // that all O_CLOEXEC file descriptors have already been closed and thus - // the second execve(2) from runc-dmz cannot access internal file - // descriptors from runc. - if err := utils.UnsafeCloseFrom(l.config.PassedFilesCount + 3); err != nil { - return err - } return system.Exec(name, l.config.Args[0:], os.Environ()) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go b/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go index 16edc6ba6d9..e1d6eb18034 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go @@ -31,12 +31,12 @@ func (p ParentDeathSignal) Set() error { return SetParentDeathSignal(uintptr(p)) } -// Deprecated: Execv is not used in runc anymore, it will be removed in v1.2.0. func Execv(cmd string, args []string, env []string) error { name, err := exec.LookPath(cmd) if err != nil { return err } + return Exec(name, args, env) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux.go deleted file mode 100644 index 4595fa82aa1..00000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build go1.23 - -package system - -import ( - "syscall" -) - -// ClearRlimitNofileCache clears go runtime's nofile rlimit cache. The argument -// is process RLIMIT_NOFILE values. Relies on go.dev/cl/588076. -func ClearRlimitNofileCache(lim *syscall.Rlimit) { - // Ignore the return values since we only need to clean the cache, - // the limit is going to be set via unix.Prlimit elsewhere. - _ = syscall.Setrlimit(syscall.RLIMIT_NOFILE, lim) -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux_go122.go b/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux_go122.go deleted file mode 100644 index 674e44bd8f7..00000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_linux_go122.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build go1.19 && !go1.23 - -// TODO: remove this file once go 1.22 is no longer supported. - -package system - -import ( - "sync/atomic" - "syscall" - _ "unsafe" // Needed for go:linkname to work. -) - -//go:linkname syscallOrigRlimitNofile syscall.origRlimitNofile -var syscallOrigRlimitNofile atomic.Pointer[syscall.Rlimit] - -// ClearRlimitNofileCache clears go runtime's nofile rlimit cache. -// The argument is process RLIMIT_NOFILE values. -func ClearRlimitNofileCache(_ *syscall.Rlimit) { - // As reported in issue #4195, the new version of go runtime(since 1.19) - // will cache rlimit-nofile. Before executing execve, the rlimit-nofile - // of the process will be restored with the cache. In runc, this will - // cause the rlimit-nofile setting by the parent process for the container - // to become invalid. It can be solved by clearing this cache. But - // unfortunately, go stdlib doesn't provide such function, so we need to - // link to the private var `origRlimitNofile` in package syscall to hack. - syscallOrigRlimitNofile.Store(nil) -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_stub.go b/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_stub.go deleted file mode 100644 index 96200df596c..00000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/system/rlimit_stub.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build !go1.19 - -package system - -import "syscall" - -func ClearRlimitNofileCache(_ *syscall.Rlimit) {} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go index 198c4936795..984466d1ab5 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go @@ -197,6 +197,7 @@ func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) { for { var line []byte line, isPrefix, err = rd.ReadLine() + if err != nil { // We should return no error if EOF is reached // without a match. diff --git a/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps.c b/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps.c deleted file mode 100644 index 84f2c6188c3..00000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps.c +++ /dev/null @@ -1,79 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include - -/* - * All of the code here is run inside an aync-signal-safe context, so we need - * to be careful to not call any functions that could cause issues. In theory, - * since we are a Go program, there are fewer restrictions in practice, it's - * better to be safe than sorry. - * - * The only exception is exit, which we need to call to make sure we don't - * return into runc. - */ - -void bail(int pipefd, const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - vdprintf(pipefd, fmt, args); - va_end(args); - - exit(1); -} - -int spawn_userns_cat(char *userns_path, char *path, int outfd, int errfd) -{ - char buffer[4096] = { 0 }; - - pid_t child = fork(); - if (child != 0) - return child; - /* in child */ - - /* Join the target userns. */ - int nsfd = open(userns_path, O_RDONLY); - if (nsfd < 0) - bail(errfd, "open userns path %s failed: %m", userns_path); - - int err = setns(nsfd, CLONE_NEWUSER); - if (err < 0) - bail(errfd, "setns %s failed: %m", userns_path); - - close(nsfd); - - /* Pipe the requested file contents. */ - int fd = open(path, O_RDONLY); - if (fd < 0) - bail(errfd, "open %s in userns %s failed: %m", path, userns_path); - - int nread, ntotal = 0; - while ((nread = read(fd, buffer, sizeof(buffer))) != 0) { - if (nread < 0) - bail(errfd, "read bytes from %s failed (after %d total bytes read): %m", path, ntotal); - ntotal += nread; - - int nwritten = 0; - while (nwritten < nread) { - int n = write(outfd, buffer, nread - nwritten); - if (n < 0) - bail(errfd, "write %d bytes from %s failed (after %d bytes written): %m", - nread - nwritten, path, nwritten); - nwritten += n; - } - if (nread != nwritten) - bail(errfd, "mismatch for bytes read and written: %d read != %d written", nread, nwritten); - } - - close(fd); - close(outfd); - close(errfd); - - /* We must exit here, otherwise we would return into a forked runc. */ - exit(0); -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps_linux.go deleted file mode 100644 index 7a8c2b023b3..00000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/userns/userns_maps_linux.go +++ /dev/null @@ -1,186 +0,0 @@ -//go:build linux - -package userns - -import ( - "bufio" - "bytes" - "fmt" - "io" - "os" - "unsafe" - - "github.com/opencontainers/runc/libcontainer/configs" - "github.com/sirupsen/logrus" -) - -/* -#include -extern int spawn_userns_cat(char *userns_path, char *path, int outfd, int errfd); -*/ -import "C" - -func parseIdmapData(data []byte) (ms []configs.IDMap, err error) { - scanner := bufio.NewScanner(bytes.NewReader(data)) - for scanner.Scan() { - var m configs.IDMap - line := scanner.Text() - if _, err := fmt.Sscanf(line, "%d %d %d", &m.ContainerID, &m.HostID, &m.Size); err != nil { - return nil, fmt.Errorf("parsing id map failed: invalid format in line %q: %w", line, err) - } - ms = append(ms, m) - } - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("parsing id map failed: %w", err) - } - return ms, nil -} - -// Do something equivalent to nsenter --user= cat , but more -// efficiently. Returns the contents of the requested file from within the user -// namespace. -func spawnUserNamespaceCat(nsPath string, path string) ([]byte, error) { - rdr, wtr, err := os.Pipe() - if err != nil { - return nil, fmt.Errorf("create pipe for userns spawn failed: %w", err) - } - defer rdr.Close() - defer wtr.Close() - - errRdr, errWtr, err := os.Pipe() - if err != nil { - return nil, fmt.Errorf("create error pipe for userns spawn failed: %w", err) - } - defer errRdr.Close() - defer errWtr.Close() - - cNsPath := C.CString(nsPath) - defer C.free(unsafe.Pointer(cNsPath)) - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - childPid := C.spawn_userns_cat(cNsPath, cPath, C.int(wtr.Fd()), C.int(errWtr.Fd())) - - if childPid < 0 { - return nil, fmt.Errorf("failed to spawn fork for userns") - } else if childPid == 0 { - // this should never happen - panic("runc executing inside fork child -- unsafe state!") - } - - // We are in the parent -- close the write end of the pipe before reading. - wtr.Close() - output, err := io.ReadAll(rdr) - rdr.Close() - if err != nil { - return nil, fmt.Errorf("reading from userns spawn failed: %w", err) - } - - // Ditto for the error pipe. - errWtr.Close() - errOutput, err := io.ReadAll(errRdr) - errRdr.Close() - if err != nil { - return nil, fmt.Errorf("reading from userns spawn error pipe failed: %w", err) - } - errOutput = bytes.TrimSpace(errOutput) - - // Clean up the child. - child, err := os.FindProcess(int(childPid)) - if err != nil { - return nil, fmt.Errorf("could not find userns spawn process: %w", err) - } - state, err := child.Wait() - if err != nil { - return nil, fmt.Errorf("failed to wait for userns spawn process: %w", err) - } - if !state.Success() { - errStr := string(errOutput) - if errStr == "" { - errStr = fmt.Sprintf("unknown error (status code %d)", state.ExitCode()) - } - return nil, fmt.Errorf("userns spawn: %s", errStr) - } else if len(errOutput) > 0 { - // We can just ignore weird output in the error pipe if the process - // didn't bail(), but for completeness output for debugging. - logrus.Debugf("userns spawn succeeded but unexpected error message found: %s", string(errOutput)) - } - // The subprocess succeeded, return whatever it wrote to the pipe. - return output, nil -} - -func GetUserNamespaceMappings(nsPath string) (uidMap, gidMap []configs.IDMap, err error) { - var ( - pid int - extra rune - tryFastPath bool - ) - - // nsPath is usually of the form /proc//ns/user, which means that we - // already have a pid that is part of the user namespace and thus we can - // just use the pid to read from /proc//*id_map. - // - // Note that Sscanf doesn't consume the whole input, so we check for any - // trailing data with %c. That way, we can be sure the pattern matched - // /proc/$pid/ns/user _exactly_ iff n === 1. - if n, _ := fmt.Sscanf(nsPath, "/proc/%d/ns/user%c", &pid, &extra); n == 1 { - tryFastPath = pid > 0 - } - - for _, mapType := range []struct { - name string - idMap *[]configs.IDMap - }{ - {"uid_map", &uidMap}, - {"gid_map", &gidMap}, - } { - var mapData []byte - - if tryFastPath { - path := fmt.Sprintf("/proc/%d/%s", pid, mapType.name) - data, err := os.ReadFile(path) - if err != nil { - // Do not error out here -- we need to try the slow path if the - // fast path failed. - logrus.Debugf("failed to use fast path to read %s from userns %s (error: %s), falling back to slow userns-join path", mapType.name, nsPath, err) - } else { - mapData = data - } - } else { - logrus.Debugf("cannot use fast path to read %s from userns %s, falling back to slow userns-join path", mapType.name, nsPath) - } - - if mapData == nil { - // We have to actually join the namespace if we cannot take the - // fast path. The path is resolved with respect to the child - // process, so just use /proc/self. - data, err := spawnUserNamespaceCat(nsPath, "/proc/self/"+mapType.name) - if err != nil { - return nil, nil, err - } - mapData = data - } - idMap, err := parseIdmapData(mapData) - if err != nil { - return nil, nil, fmt.Errorf("failed to parse %s of userns %s: %w", mapType.name, nsPath, err) - } - *mapType.idMap = idMap - } - - return uidMap, gidMap, nil -} - -// IsSameMapping returns whether or not the two id mappings are the same. Note -// that if the order of the mappings is different, or a mapping has been split, -// the mappings will be considered different. -func IsSameMapping(a, b []configs.IDMap) bool { - if len(a) != len(b) { - return false - } - for idx := range a { - if a[idx] != b[idx] { - return false - } - } - return true -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go index bf3237a2911..220d0b43937 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go @@ -7,7 +7,6 @@ import ( "fmt" "os" "strconv" - _ "unsafe" // for go:linkname "golang.org/x/sys/unix" ) @@ -24,11 +23,9 @@ func EnsureProcHandle(fh *os.File) error { return nil } -type fdFunc func(fd int) - -// fdRangeFrom calls the passed fdFunc for each file descriptor that is open in -// the current process. -func fdRangeFrom(minFd int, fn fdFunc) error { +// CloseExecFrom applies O_CLOEXEC to all file descriptors currently open for +// the process (except for those below the given fd value). +func CloseExecFrom(minFd int) error { fdDir, err := os.Open("/proc/self/fd") if err != nil { return err @@ -53,60 +50,15 @@ func fdRangeFrom(minFd int, fn fdFunc) error { if fd < minFd { continue } - // Ignore the file descriptor we used for readdir, as it will be closed - // when we return. - if uintptr(fd) == fdDir.Fd() { - continue - } - // Run the closure. - fn(fd) + // Intentionally ignore errors from unix.CloseOnExec -- the cases where + // this might fail are basically file descriptors that have already + // been closed (including and especially the one that was created when + // os.ReadDir did the "opendir" syscall). + unix.CloseOnExec(fd) } return nil } -// CloseExecFrom sets the O_CLOEXEC flag on all file descriptors greater or -// equal to minFd in the current process. -func CloseExecFrom(minFd int) error { - return fdRangeFrom(minFd, unix.CloseOnExec) -} - -//go:linkname runtime_IsPollDescriptor internal/poll.IsPollDescriptor - -// In order to make sure we do not close the internal epoll descriptors the Go -// runtime uses, we need to ensure that we skip descriptors that match -// "internal/poll".IsPollDescriptor. Yes, this is a Go runtime internal thing, -// unfortunately there's no other way to be sure we're only keeping the file -// descriptors the Go runtime needs. Hopefully nothing blows up doing this... -func runtime_IsPollDescriptor(fd uintptr) bool //nolint:revive - -// UnsafeCloseFrom closes all file descriptors greater or equal to minFd in the -// current process, except for those critical to Go's runtime (such as the -// netpoll management descriptors). -// -// NOTE: That this function is incredibly dangerous to use in most Go code, as -// closing file descriptors from underneath *os.File handles can lead to very -// bad behaviour (the closed file descriptor can be re-used and then any -// *os.File operations would apply to the wrong file). This function is only -// intended to be called from the last stage of runc init. -func UnsafeCloseFrom(minFd int) error { - // We must not close some file descriptors. - return fdRangeFrom(minFd, func(fd int) { - if runtime_IsPollDescriptor(uintptr(fd)) { - // These are the Go runtimes internal netpoll file descriptors. - // These file descriptors are operated on deep in the Go scheduler, - // and closing those files from underneath Go can result in panics. - // There is no issue with keeping them because they are not - // executable and are not useful to an attacker anyway. Also we - // don't have any choice. - return - } - // There's nothing we can do about errors from close(2), and the - // only likely error to be seen is EBADF which indicates the fd was - // already closed (in which case, we got what we wanted). - _ = unix.Close(fd) - }) -} - // NewSockPair returns a new unix socket pair func NewSockPair(name string) (parent *os.File, child *os.File, err error) { fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) diff --git a/vendor/modules.txt b/vendor/modules.txt index e7acdf5359e..76b02a15653 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -827,8 +827,8 @@ github.com/opencontainers/go-digest ## explicit; go 1.18 github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go/v1 -# github.com/opencontainers/runc v1.1.13 -## explicit; go 1.18 +# github.com/opencontainers/runc v1.1.10 +## explicit; go 1.17 github.com/opencontainers/runc/libcontainer github.com/opencontainers/runc/libcontainer/apparmor github.com/opencontainers/runc/libcontainer/capabilities @@ -1169,7 +1169,7 @@ golang.org/x/exp/slices golang.org/x/mod/internal/lazyregexp golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/net v0.24.0 +# golang.org/x/net v0.23.0 ## explicit; go 1.18 golang.org/x/net/bpf golang.org/x/net/context