mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
Merge pull request #2647 from cyphar/procfs-masking-nested
rootfs: handle nested procfs mounts for MS_MOVE
This commit is contained in:
@@ -809,24 +809,46 @@ func pivotRoot(rootfs string) error {
|
||||
}
|
||||
|
||||
func msMoveRoot(rootfs string) error {
|
||||
// Before we move the root and chroot we have to mask all "full" sysfs and
|
||||
// procfs mounts which exist on the host. This is because while the kernel
|
||||
// has protections against mounting procfs if it has masks, when using
|
||||
// chroot(2) the *host* procfs mount is still reachable in the mount
|
||||
// namespace and the kernel permits procfs mounts inside --no-pivot
|
||||
// containers.
|
||||
//
|
||||
// Users shouldn't be using --no-pivot except in exceptional circumstances,
|
||||
// but to avoid such a trivial security flaw we apply a best-effort
|
||||
// protection here. The kernel only allows a mount of a pseudo-filesystem
|
||||
// like procfs or sysfs if there is a *full* mount (the root of the
|
||||
// filesystem is mounted) without any other locked mount points covering a
|
||||
// subtree of the mount.
|
||||
//
|
||||
// So we try to unmount (or mount tmpfs on top of) any mountpoint which is
|
||||
// a full mount of either sysfs or procfs (since those are the most
|
||||
// concerning filesystems to us).
|
||||
mountinfos, err := mountinfo.GetMounts(func(info *mountinfo.Info) (skip, stop bool) {
|
||||
skip = false
|
||||
stop = false
|
||||
// Collect every sysfs and proc file systems, except those under the container rootfs
|
||||
if (info.FSType != "proc" && info.FSType != "sysfs") || strings.HasPrefix(info.Mountpoint, rootfs) {
|
||||
// Collect every sysfs and procfs filesystem, except for those which
|
||||
// are non-full mounts or are inside the rootfs of the container.
|
||||
if info.Root != "/" ||
|
||||
(info.FSType != "proc" && info.FSType != "sysfs") ||
|
||||
strings.HasPrefix(info.Mountpoint, rootfs) {
|
||||
skip = true
|
||||
return
|
||||
}
|
||||
return
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, info := range mountinfos {
|
||||
p := info.Mountpoint
|
||||
// Be sure umount events are not propagated to the host.
|
||||
if err := unix.Mount("", p, "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil {
|
||||
if err == unix.ENOENT {
|
||||
// If the mountpoint doesn't exist that means that we've
|
||||
// already blasted away some parent directory of the mountpoint
|
||||
// and so we don't care about this error.
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := unix.Unmount(p, unix.MNT_DETACH); err != nil {
|
||||
@@ -841,6 +863,8 @@ func msMoveRoot(rootfs string) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move the rootfs on top of "/" in our mount namespace.
|
||||
if err := unix.Mount(rootfs, "/", "", unix.MS_MOVE, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user