3bb17a
From 28a697cce3e4f905dca700eda81d681a30eef9cd Mon Sep 17 00:00:00 2001
3bb17a
From: Giuseppe Scrivano <gscrivan@redhat.com>
3bb17a
Date: Fri, 11 Jan 2019 21:53:45 +0100
3bb17a
Subject: [PATCH] rootfs: umount all procfs and sysfs with --no-pivot
3bb17a
3bb17a
When creating a new user namespace, the kernel doesn't allow to mount
3bb17a
a new procfs or sysfs file system if there is not already one instance
3bb17a
fully visible in the current mount namespace.
3bb17a
3bb17a
When using --no-pivot we were effectively inhibiting this protection
3bb17a
from the kernel, as /proc and /sys from the host are still present in
3bb17a
the container mount namespace.
3bb17a
3bb17a
A container without full access to /proc could then create a new user
3bb17a
namespace, and from there able to mount a fully visible /proc, bypassing
3bb17a
the limitations in the container.
3bb17a
3bb17a
A simple reproducer for this issue is:
3bb17a
3bb17a
unshare -mrfp sh -c "mount -t proc none /proc && echo c > /proc/sysrq-trigger"
3bb17a
3bb17a
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
3bb17a
---
3bb17a
 libcontainer/rootfs_linux.go | 35 +++++++++++++++++++++++++++++++++++
3bb17a
 1 file changed, 35 insertions(+)
3bb17a
3bb17a
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
3bb17a
index e7c2f8ada..6bd6da74a 100644
3bb17a
--- a/libcontainer/rootfs_linux.go
3bb17a
+++ b/libcontainer/rootfs_linux.go
3bb17a
@@ -748,6 +748,41 @@ func pivotRoot(rootfs string) error {
3bb17a
 }
3bb17a
 
3bb17a
 func msMoveRoot(rootfs string) error {
3bb17a
+	mountinfos, err := mount.GetMounts()
3bb17a
+	if err != nil {
3bb17a
+		return err
3bb17a
+	}
3bb17a
+
3bb17a
+	absRootfs, err := filepath.Abs(rootfs)
3bb17a
+	if err != nil {
3bb17a
+		return err
3bb17a
+	}
3bb17a
+
3bb17a
+	for _, info := range mountinfos {
3bb17a
+		p, err := filepath.Abs(info.Mountpoint)
3bb17a
+		if err != nil {
3bb17a
+			return err
3bb17a
+		}
3bb17a
+		// Umount every syfs and proc file systems, except those under the container rootfs
3bb17a
+		if (info.Fstype != "proc" && info.Fstype != "sysfs") || filepath.HasPrefix(p, absRootfs) {
3bb17a
+			continue
3bb17a
+		}
3bb17a
+		// Be sure umount events are not propagated to the host.
3bb17a
+		if err := unix.Mount("", p, "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil {
3bb17a
+			return err
3bb17a
+		}
3bb17a
+		if err := unix.Unmount(p, unix.MNT_DETACH); err != nil {
3bb17a
+			if err != unix.EINVAL && err != unix.EPERM {
3bb17a
+				return err
3bb17a
+			} else {
3bb17a
+				// If we have not privileges for umounting (e.g. rootless), then
3bb17a
+				// cover the path.
3bb17a
+				if err := unix.Mount("tmpfs", p, "tmpfs", 0, ""); err != nil {
3bb17a
+					return err
3bb17a
+				}
3bb17a
+			}
3bb17a
+		}
3bb17a
+	}
3bb17a
 	if err := unix.Mount(rootfs, "/", "", unix.MS_MOVE, ""); err != nil {
3bb17a
 		return err
3bb17a
 	}