Blob Blame History Raw
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
 		}
 	}