You've already forked runc
mirror of
https://github.com/opencontainers/runc.git
synced 2025-07-04 02:42:31 +03:00
This is an additional mitigation for CVE-2019-16884. The primary problem is that Docker can be coerced into bind-mounting a file system on top of /proc (resulting in label-related writes to /proc no longer happening). While we are working on mitigations against permitting the mounts, this helps avoid our code from being tricked into writing to non-procfs files. This is not a perfect solution (after all, there might be a bind-mount of a different procfs file over the target) but in order to exploit that you would need to be able to tweak a config.json pretty specifically (which thankfully Docker doesn't allow). Specifically this stops AppArmor from not labeling a process silently due to /proc/self/attr/... being incorrectly set, and stops any accidental fd leaks because /proc/self/fd/... is not real. Signed-off-by: Aleksa Sarai <asarai@suse.de>
69 lines
1.7 KiB
Go
69 lines
1.7 KiB
Go
// +build !windows
|
|
|
|
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// EnsureProcHandle returns whether or not the given file handle is on procfs.
|
|
func EnsureProcHandle(fh *os.File) error {
|
|
var buf unix.Statfs_t
|
|
if err := unix.Fstatfs(int(fh.Fd()), &buf); err != nil {
|
|
return fmt.Errorf("ensure %s is on procfs: %v", fh.Name(), err)
|
|
}
|
|
if buf.Type != unix.PROC_SUPER_MAGIC {
|
|
return fmt.Errorf("%s is not on procfs", fh.Name())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 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
|
|
}
|
|
defer fdDir.Close()
|
|
|
|
if err := EnsureProcHandle(fdDir); err != nil {
|
|
return err
|
|
}
|
|
|
|
fdList, err := fdDir.Readdirnames(-1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, fdStr := range fdList {
|
|
fd, err := strconv.Atoi(fdStr)
|
|
// Ignore non-numeric file names.
|
|
if err != nil {
|
|
continue
|
|
}
|
|
// Ignore descriptors lower than our specified minimum.
|
|
if fd < minFd {
|
|
continue
|
|
}
|
|
// 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
|
|
// ioutil.ReadDir did the "opendir" syscall).
|
|
unix.CloseOnExec(fd)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 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)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return os.NewFile(uintptr(fds[1]), name+"-p"), os.NewFile(uintptr(fds[0]), name+"-c"), nil
|
|
}
|