Skip to content

Commit

Permalink
rootfs: umount all procfs and sysfs with --no-pivot
Browse files Browse the repository at this point in the history
When creating a new user namespace, the kernel doesn't allow to mount
a new procfs or sysfs file system if there is not already one instance
fully visible in the current mount namespace.

When using --no-pivot we were effectively inhibiting this protection
from the kernel, as /proc and /sys from the host are still present in
the container mount namespace.

A container without full access to /proc could then create a new user
namespace, and from there able to mount a fully visible /proc, bypassing
the limitations in the container.

A simple reproducer for this issue is:

unshare -mrfp sh -c "mount -t proc none /proc && echo c > /proc/sysrq-trigger"

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
  • Loading branch information
giuseppe committed Jan 11, 2019
1 parent bbb17ef commit 5d8596f
Showing 1 changed file with 36 additions and 0 deletions.
36 changes: 36 additions & 0 deletions libcontainer/rootfs_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"path"
"path/filepath"
"strings"
"syscall"
"time"

"github.com/cyphar/filepath-securejoin"
Expand Down Expand Up @@ -748,6 +749,41 @@ func pivotRoot(rootfs string) error {
}

func msMoveRoot(rootfs string) error {
mountinfos, err := mount.GetMounts()
if err != nil {
return err
}

absRootfs, err := filepath.Abs(rootfs)
if err != nil {
return err
}

for _, info := range mountinfos {
p, err := filepath.Abs(info.Mountpoint)
if err != nil {
return err
}
// Umount every syfs and proc file systems, except those under the container rootfs
if (info.Fstype != "proc" && info.Fstype != "sysfs") || filepath.HasPrefix(p, absRootfs) {
continue
}
// Be sure umount events are not propagated to the host.
if err := unix.Mount("", p, "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil {
return err
}
if err := unix.Unmount(p, unix.MNT_DETACH); err != nil {
if err.(syscall.Errno) != unix.EINVAL {
return err
} else {
// If we have not privileges for umounting (e.g. rootless), then
// cover the path.
if err := unix.Mount("tmpfs", p, "tmpfs", 0, ""); err != nil {
return err
}
}
}
}
if err := unix.Mount(rootfs, "/", "", unix.MS_MOVE, ""); err != nil {
return err
}
Expand Down

0 comments on commit 5d8596f

Please sign in to comment.