49a657
From 3291d66b98445bd7f7d02eac7f2bca2ac2c56942 Mon Sep 17 00:00:00 2001
49a657
From: Aleksa Sarai <asarai@suse.de>
49a657
Date: Sat, 21 Dec 2019 23:40:17 +1100
49a657
Subject: [PATCH] rootfs: do not permit /proc mounts to non-directories
49a657
49a657
mount(2) will blindly follow symlinks, which is a problem because it
49a657
allows a malicious container to trick runc into mounting /proc to an
49a657
entirely different location (and thus within the attacker's control for
49a657
a rename-exchange attack).
49a657
49a657
This is just a hotfix (to "stop the bleeding"), and the more complete
49a657
fix would be finish libpathrs and port runc to it (to avoid these types
49a657
of attacks entirely, and defend against a variety of other /proc-related
49a657
attacks). It can be bypased by someone having "/" be a volume controlled
49a657
by another container.
49a657
49a657
Fixes: CVE-2019-19921
49a657
Signed-off-by: Aleksa Sarai <asarai@suse.de>
49a657
---
49a657
 libcontainer/rootfs_linux.go | 12 ++++++++++++
49a657
 1 file changed, 12 insertions(+)
49a657
49a657
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
49a657
index 291021440..106c4c2b9 100644
49a657
--- a/libcontainer/rootfs_linux.go
49a657
+++ b/libcontainer/rootfs_linux.go
49a657
@@ -299,6 +299,18 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b
49a657
 
49a657
 	switch m.Device {
49a657
 	case "proc", "sysfs":
49a657
+		// If the destination already exists and is not a directory, we bail
49a657
+		// out This is to avoid mounting through a symlink or similar -- which
49a657
+		// has been a "fun" attack scenario in the past.
49a657
+		// TODO: This won't be necessary once we switch to libpathrs and we can
49a657
+		//       stop all of these symlink-exchange attacks.
49a657
+		if fi, err := os.Lstat(dest); err != nil {
49a657
+			if !os.IsNotExist(err) {
49a657
+				return err
49a657
+			}
49a657
+		} else if fi.Mode()&os.ModeDir == 0 {
49a657
+			return fmt.Errorf("filesystem %q must be mounted on ordinary directory", m.Device)
49a657
+		}
49a657
 		if err := os.MkdirAll(dest, 0755); err != nil {
49a657
 			return err
49a657
 		}