From 0b0bb50e4ecdebfb2646adb57e53972663947320 Mon Sep 17 00:00:00 2001 From: wangfengtu Date: Wed, 27 Mar 2019 15:28:03 +0800 Subject: [PATCH] runc: Fix mountpoint leak and pivot_root error reason:We have no way to get exact /proc/self/mountinfo infomation because it can change if other process mount/umount mountpoint. So runc sometimes cannot get container's mountpoint when runc try to make mountpoint private. This can cause mountpoint leak and pivot_root error, runc error out like this: ``` Handler for POST /v1.23/containers/1d265651cb1d5475bcb7d5db21679757d5527d44a41c102c6aa4bddaa518c547/start returned error: oci runtime error: container_linux.go:317: starting container process caused \"process_linux.go:358: container init caused \\\"rootfs_linux.go:105: jailing process inside rootfs caused \\\\\\\"pivot_root invalid argument\\\\\\\"\\\"\"\n ``` Change-Id: Icde1638af6ad45c762c11fc8a2b8a969b6306ca5 Signed-off-by: wangfengtu --- libcontainer/rootfs_linux.go | 32 ++++++++++++---------- .../docker/docker/pkg/mount/mountinfo_linux.go | 7 +++-- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index 3dd5113..53797e9 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -24,7 +24,10 @@ import ( "github.com/opencontainers/selinux/go-selinux/label" ) -const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV +const ( + defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV + maxRetryTimes = 5 +) // needsSetupDev returns true if /dev needs to be set up. func needsSetupDev(config *configs.Config) bool { @@ -545,23 +548,16 @@ func getMountInfo(mountinfo []*mount.Info, dir string) *mount.Info { // Get the parent mount point of directory passed in as argument. Also return // optional fields. func getParentMount(rootfs string) (string, string, error) { - var path string - - mountinfos, err := mount.GetMounts() - if err != nil { - return "", "", err - } - - mountinfo := getMountInfo(mountinfos, rootfs) - if mountinfo != nil { - return rootfs, mountinfo.Optional, nil - } + retryTimes := maxRetryTimes + path := rootfs - path = rootfs for { - path = filepath.Dir(path) + mountinfos, err := mount.GetMounts() + if err != nil { + return "", "", err + } - mountinfo = getMountInfo(mountinfos, path) + mountinfo := getMountInfo(mountinfos, path) if mountinfo != nil { return path, mountinfo.Optional, nil } @@ -569,6 +565,12 @@ func getParentMount(rootfs string) (string, string, error) { if path == "/" { break } + + retryTimes-- + if retryTimes == 0 { + retryTimes = maxRetryTimes + path = filepath.Dir(path) + } } // If we are here, we did not find parent mount. Something is wrong. diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go index be69fee..b74773f 100644 --- a/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go +++ b/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go @@ -4,8 +4,10 @@ package mount import ( "bufio" + "bytes" "fmt" "io" + "io/ioutil" "os" "strings" ) @@ -31,13 +33,12 @@ const ( // Parse /proc/self/mountinfo because comparing Dev and ino does not work from // bind mounts func parseMountTable() ([]*Info, error) { - f, err := os.Open("/proc/self/mountinfo") + content, err := ioutil.ReadFile("/proc/self/mountinfo") if err != nil { return nil, err } - defer f.Close() - return parseInfoFile(f) + return parseInfoFile(bytes.NewReader(content)) } func parseInfoFile(r io.Reader) ([]*Info, error) { -- 2.7.4