From 525471fe0042e8cb68e328bf10d87559579dab3e Mon Sep 17 00:00:00 2001 From: Cedric Clerget Date: Wed, 26 Jun 2019 14:29:45 +0200 Subject: [PATCH] Attempt to remount bind point with user namespace but ignore permission denied errors returned and warn users if the bind mount need requested to be mounted read-only. Co-Authored-By: Marcelo Magallon --- .../engines/singularity/container_linux.go | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/internal/pkg/runtime/engines/singularity/container_linux.go b/internal/pkg/runtime/engines/singularity/container_linux.go index 845fb3dc93..2bb0acb146 100644 --- a/internal/pkg/runtime/engines/singularity/container_linux.go +++ b/internal/pkg/runtime/engines/singularity/container_linux.go @@ -540,6 +540,25 @@ func (c *container) mountGeneric(mnt *mount.Point) (err error) { } } _, err = c.rpcOps.Mount(source, dest, mnt.Type, flags, optsString) + // when using user namespace we always try to apply mount flags with + // remount, then if we get a permission denied error, we continue + // execution by ignoring the error and warn user if the bind mount + // need to be mounted read-only + if remount && err != nil && c.userNS { + // this needs to compare error strings because we are dropping + // the original error value in the RPC call. In order to keep + // the original error values, we would have to add them to the + // corresponding struct passed over RPC and add the necessary + // GOB encoding / decoding functions. + if err.Error() == syscall.Errno(syscall.EPERM).Error() { + if flags&syscall.MS_RDONLY != 0 { + sylog.Warningf("Could not remount %s read-only: %s", dest, err) + } else { + sylog.Verbosef("Could not remount %s: %s", dest, err) + } + return nil + } + } return err } @@ -1292,13 +1311,14 @@ func (c *container) addUserbindsMount(system *mount.System) error { devicesMounted := 0 devPrefix := "/dev" userBindControl := c.engine.EngineConfig.File.UserBindControl - flags := uintptr(syscall.MS_BIND | c.suidFlag | syscall.MS_NODEV | syscall.MS_REC) + defaultFlags := uintptr(syscall.MS_BIND | c.suidFlag | syscall.MS_NODEV | syscall.MS_REC) if len(c.engine.EngineConfig.GetBindPath()) == 0 { return nil } for _, b := range c.engine.EngineConfig.GetBindPath() { + flags := defaultFlags splitted := strings.Split(b, ":") src, err := filepath.Abs(splitted[0]) @@ -1348,13 +1368,12 @@ func (c *container) addUserbindsMount(system *mount.System) error { sylog.Debugf("Adding %s to mount list\n", src) - if err := system.Points.AddBind(mount.UserbindsTag, src, dst, flags); err != nil && err == mount.ErrMountExists { + if err := system.Points.AddBind(mount.UserbindsTag, src, dst, flags); err == mount.ErrMountExists { sylog.Warningf("destination %s already in mount list: %s", src, err) } else if err != nil { return fmt.Errorf("unable to add %s to mount list: %s", src, err) } else { system.Points.AddRemount(mount.UserbindsTag, dst, flags) - flags &^= syscall.MS_RDONLY } }