From 525471fe0042e8cb68e328bf10d87559579dab3e Mon Sep 17 00:00:00 2001
From: Cedric Clerget <cedric.clerget@gmail.com>
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 <marcelo.magallon@gmail.com>
---
.../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
}
}