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