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