From 04d40d68e7c392f3096146abffb5885b4b053ac6 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 11 Jan 2019 21:53:45 +0100 Subject: [PATCH] rootfs: umount all procfs and sysfs with --no-pivot 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 (cherry picked from commit 28a697cce3e4f905dca700eda81d681a30eef9cd) Signed-off-by: Sebastiaan van Stijn --- libcontainer/rootfs_linux.go | 39 ++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index 710f11d3ade..0c5f5a24a86 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -707,9 +707,48 @@ 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 := syscall.Mount("", p, "", syscall.MS_SLAVE|syscall.MS_REC, ""); err != nil { + return err + } + if err := syscall.Unmount(p, syscall.MNT_DETACH); err != nil { + if err != syscall.EINVAL && err != syscall.EPERM { + return err + } else { + // If we have not privileges for umounting (e.g. rootless), then + // cover the path. + if err := syscall.Mount("tmpfs", p, "tmpfs", 0, ""); err != nil { + return err + } + } + } + } if err := syscall.Mount(rootfs, "/", "", syscall.MS_MOVE, ""); err != nil { return err } + return chroot(rootfs) +} + +func chroot(rootfs string) error { if err := syscall.Chroot("."); err != nil { return err }