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 <dongsu@kinvolk.io>
This commit is contained in:
Dongsu Park 2018-06-08 13:31:49 +02:00
parent dd56ece823
commit da16461dc5
1 changed files with 34 additions and 0 deletions

View File

@ -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 {