Skip to content

Commit 89c93dd

Browse files
committed
cgroup: plug leaks of /sys/fs/cgroup handle
We auto-close this file descriptor in the final exec step, but it's probably a good idea to not possibly leak the file descriptor to "runc init" (we've had issues like this in the past) especially since it is a directory handle from the host mount namespace. In practice, on runc 1.1 this does leak to "runc init" but on main the handle has a low enough file descriptor that it gets clobbered by the ForkExec of "runc init". OPEN_TREE_CLONE would let us protect this handle even further, but the performance impact of creating an anonymous mount namespace is probably not worth it. Also, switch to using an *os.File for the handle so if it goes out of scope during setup (i.e. an error occurs during setup) it will get cleaned up by the GC. Fixes: GHSA-xr7r-f8xq-vfvv CVE-2024-21626 Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
1 parent f2f1621 commit 89c93dd

File tree

1 file changed

+16
-15
lines changed

1 file changed

+16
-15
lines changed

libcontainer/cgroups/file.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,16 @@ var (
6666
// TestMode is set to true by unit tests that need "fake" cgroupfs.
6767
TestMode bool
6868

69-
cgroupFd int = -1
70-
prepOnce sync.Once
71-
prepErr error
72-
resolveFlags uint64
69+
cgroupRootHandle *os.File
70+
prepOnce sync.Once
71+
prepErr error
72+
resolveFlags uint64
7373
)
7474

7575
func prepareOpenat2() error {
7676
prepOnce.Do(func() {
7777
fd, err := unix.Openat2(-1, cgroupfsDir, &unix.OpenHow{
78-
Flags: unix.O_DIRECTORY | unix.O_PATH,
78+
Flags: unix.O_DIRECTORY | unix.O_PATH | unix.O_CLOEXEC,
7979
})
8080
if err != nil {
8181
prepErr = &os.PathError{Op: "openat2", Path: cgroupfsDir, Err: err}
@@ -86,15 +86,16 @@ func prepareOpenat2() error {
8686
}
8787
return
8888
}
89+
file := os.NewFile(uintptr(fd), cgroupfsDir)
90+
8991
var st unix.Statfs_t
90-
if err = unix.Fstatfs(fd, &st); err != nil {
92+
if err := unix.Fstatfs(int(file.Fd()), &st); err != nil {
9193
prepErr = &os.PathError{Op: "statfs", Path: cgroupfsDir, Err: err}
9294
logrus.Warnf("falling back to securejoin: %s", prepErr)
9395
return
9496
}
9597

96-
cgroupFd = fd
97-
98+
cgroupRootHandle = file
9899
resolveFlags = unix.RESOLVE_BENEATH | unix.RESOLVE_NO_MAGICLINKS
99100
if st.Type == unix.CGROUP2_SUPER_MAGIC {
100101
// cgroupv2 has a single mountpoint and no "cpu,cpuacct" symlinks
@@ -121,29 +122,29 @@ func openFile(dir, file string, flags int) (*os.File, error) {
121122
return openFallback(path, flags, mode)
122123
}
123124

124-
fd, err := unix.Openat2(cgroupFd, relPath,
125+
fd, err := unix.Openat2(int(cgroupRootHandle.Fd()), relPath,
125126
&unix.OpenHow{
126127
Resolve: resolveFlags,
127128
Flags: uint64(flags) | unix.O_CLOEXEC,
128129
Mode: uint64(mode),
129130
})
130131
if err != nil {
131132
err = &os.PathError{Op: "openat2", Path: path, Err: err}
132-
// Check if cgroupFd is still opened to cgroupfsDir
133+
// Check if cgroupRootHandle is still opened to cgroupfsDir
133134
// (happens when this package is incorrectly used
134135
// across the chroot/pivot_root/mntns boundary, or
135136
// when /sys/fs/cgroup is remounted).
136137
//
137138
// TODO: if such usage will ever be common, amend this
138-
// to reopen cgroupFd and retry openat2.
139-
fdPath, closer := utils.ProcThreadSelf("fd/" + strconv.Itoa(cgroupFd))
139+
// to reopen cgroupRootHandle and retry openat2.
140+
fdPath, closer := utils.ProcThreadSelf("fd/" + strconv.Itoa(int(cgroupRootHandle.Fd())))
140141
defer closer()
141142
fdDest, _ := os.Readlink(fdPath)
142143
if fdDest != cgroupfsDir {
143-
// Wrap the error so it is clear that cgroupFd
144+
// Wrap the error so it is clear that cgroupRootHandle
144145
// is opened to an unexpected/wrong directory.
145-
err = fmt.Errorf("cgroupFd %d unexpectedly opened to %s != %s: %w",
146-
cgroupFd, fdDest, cgroupfsDir, err)
146+
err = fmt.Errorf("cgroupRootHandle %d unexpectedly opened to %s != %s: %w",
147+
cgroupRootHandle.Fd(), fdDest, cgroupfsDir, err)
147148
}
148149
return nil, err
149150
}

0 commit comments

Comments
 (0)