From da16461dc5b8ffa3671f3cbc7c3a6603a2585205 Mon Sep 17 00:00:00 2001 From: Dongsu Park Date: Fri, 8 Jun 2018 13:31:49 +0200 Subject: [PATCH] libcontainer: fix a bug when setting shared rootfs propagation mode So far when the input mount flags contain `MS_SHARED`, the flag has not been applied to the container rootfs. That's because we call `rootfsParentMountPrivate()` after applying the original mount flags. As a result, the original flags are overwritten. Though it's also true that we actually need to mount the container rootfs with `MS_PRIVATE`, to avoid failure from `pivot_root()` in the Linux kernel. Thus if the mount flags contain `MS_SHARED`, we need a special case handling. First do `pivotRoot()` (or `msMoveRoot`, `chroot`) with the rootfs with a mount flag `MS_PRIVATE`. Then after `pivotRoot()`, again mount the rootfs with `MS_SHARED`. With this fix, `validation/linux_rootfs_propagation.t` of runtime-tools works well with the shared mode finally. Fixes https://github.com/opencontainers/runc/issues/1755 Signed-off-by: Dongsu Park --- libcontainer/rootfs_linux.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index 7f852efceb2..621e69c7bec 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -110,6 +110,15 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { return newSystemErrorWithCause(err, "jailing process inside rootfs") } + // mount with MS_SHARED flag does not work well with pivotRoot, because + // of the checks in the Linux kernel. So we need to first pivotRoot with + // a private rootfs, and after that make it shared. + if config.RootPropagation&unix.MS_SHARED != 0 { + if err := rootfsParentMountShared(config.Rootfs); err != nil { + return err + } + } + if setupDev { if err := reOpenDevNull(); err != nil { return newSystemErrorWithCause(err, "reopening /dev/null inside container") @@ -608,6 +617,31 @@ func rootfsParentMountPrivate(rootfs string) error { return nil } +// Make parent mount shared if it was not shared +func rootfsParentMountShared(rootfs string) error { + sharedMount := false + + parentMount, optionalOpts, err := getParentMount(rootfs) + if err != nil { + return err + } + + optsSplit := strings.Split(optionalOpts, " ") + for _, opt := range optsSplit { + if strings.HasPrefix(opt, "shared:") { + sharedMount = true + break + } + } + + // Make parent mount SHARED if it was not shared. + if !sharedMount { + return unix.Mount("", parentMount, "", unix.MS_SHARED, "") + } + + return nil +} + func prepareRoot(config *configs.Config) error { flag := unix.MS_SLAVE | unix.MS_REC if config.RootPropagation != 0 {