Repository: opencontainers/runc
Pull request #3971 (2023-08-07 14:53:43)

Revert "libct/validator: Error out on non-abs paths"
As [discussed here](https://github.com/opencontainers/runc/issues/3944#issuecomment-1669297461) it seems safer, at least for now, to revert the error and continue to throw a warning.

---

This reverts commit 881e92a3fd5eeef80bac57efbb1c822deed4f895 and adjust the code so the idmap validations are strict.

Fixes: #3944 
Updates: #3020 (There is no way to re-open it automatically, can someone re-open it?)


Patch:
diff --git a/libcontainer/configs/validate/validator.go b/libcontainer/configs/validate/validator.go
index 196b431d..cb4b32de 100644
--- a/libcontainer/configs/validate/validator.go
+++ b/libcontainer/configs/validate/validator.go
@@ -12,6 +12,7 @@ import (
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/intelrdt"
 	selinux "github.com/opencontainers/selinux/go-selinux"
+	"github.com/sirupsen/logrus"
 	"golang.org/x/sys/unix"
 )
 
@@ -28,13 +29,22 @@ func Validate(config *configs.Config) error {
 		sysctl,
 		intelrdtCheck,
 		rootlessEUIDCheck,
-		mounts,
+		mountsStrict,
 	}
 	for _, c := range checks {
 		if err := c(config); err != nil {
 			return err
 		}
 	}
+	// Relaxed validation rules for backward compatibility
+	warns := []check{
+		mounts, // TODO (runc v1.x.x): make this an error instead of a warning
+	}
+	for _, c := range warns {
+		if err := c(config); err != nil {
+			logrus.WithError(err).Warn("invalid configuration")
+		}
+	}
 	return nil
 }
 
@@ -282,19 +292,19 @@ func checkIDMapMounts(config *configs.Config, m *configs.Mount) error {
 
 func mounts(config *configs.Config) error {
 	for _, m := range config.Mounts {
-		// We upgraded this to an error in runc 1.2. We might need to
-		// revert this change if some users haven't still moved to use
-		// abs paths, in that please move this check inside
-		// checkIDMapMounts() as we do want to ensure that for idmap
-		// mounts anyways.
 		if !filepath.IsAbs(m.Destination) {
 			return fmt.Errorf("invalid mount %+v: mount destination not absolute", m)
 		}
+	}
+	return nil
+}
+
+func mountsStrict(config *configs.Config) error {
+	for _, m := range config.Mounts {
 		if err := checkIDMapMounts(config, m); err != nil {
 			return fmt.Errorf("invalid mount %+v: %w", m, err)
 		}
 	}
-
 	return nil
 }
 
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
index ac3ba183..54a2ff57 100644
--- a/libcontainer/rootfs_linux.go
+++ b/libcontainer/rootfs_linux.go
@@ -485,7 +485,7 @@ func mountToRootfs(c *mountConfig, m mountEntry) error {
 			if m.srcFD == nil {
 				return fmt.Errorf("error creating mount %+v: idmapFD is invalid, should point to a valid fd", m)
 			}
-			if err := unix.MoveMount(*m.srcFD, "", -1, dest, unix.MOVE_MOUNT_F_EMPTY_PATH); err != nil {
+			if err := unix.MoveMount(*m.srcFD, "", unix.AT_FDCWD, dest, unix.MOVE_MOUNT_F_EMPTY_PATH); err != nil {
 				return fmt.Errorf("error on unix.MoveMount %+v: %w", m, err)
 			}
 


Test patch:
diff --git a/libcontainer/configs/validate/validator_test.go b/libcontainer/configs/validate/validator_test.go
index 58aae7a6..b6b2d372 100644
--- a/libcontainer/configs/validate/validator_test.go
+++ b/libcontainer/configs/validate/validator_test.go
@@ -360,10 +360,11 @@ func TestValidateMounts(t *testing.T) {
 		isErr bool
 		dest  string
 	}{
-		{isErr: true, dest: "not/an/abs/path"},
-		{isErr: true, dest: "./rel/path"},
-		{isErr: true, dest: "./rel/path"},
-		{isErr: true, dest: "../../path"},
+		// TODO (runc v1.x.x): make these relative paths an error. See https://github.com/opencontainers/runc/pull/3004
+		{isErr: false, dest: "not/an/abs/path"},
+		{isErr: false, dest: "./rel/path"},
+		{isErr: false, dest: "./rel/path"},
+		{isErr: false, dest: "../../path"},
 
 		{isErr: false, dest: "/abs/path"},
 		{isErr: false, dest: "/abs/but/../unclean"},
@@ -514,8 +515,7 @@ func TestValidateIDMapMounts(t *testing.T) {
 			},
 		},
 		{
-			name:  "idmap mounts without abs dest path",
-			isErr: true,
+			name: "idmap mounts without abs dest path",
 			config: &configs.Config{
 				UIDMappings: mapping,
 				GIDMappings: mapping,
@@ -530,7 +530,6 @@ func TestValidateIDMapMounts(t *testing.T) {
 				},
 			},
 		},
-
 		{
 			name: "simple idmap mount",
 			config: &configs.Config{
@@ -571,7 +570,7 @@ func TestValidateIDMapMounts(t *testing.T) {
 			config := tc.config
 			config.Rootfs = "/var"
 
-			err := mounts(config)
+			err := mountsStrict(config)
 			if tc.isErr && err == nil {
 				t.Error("expected error, got nil")
 			}
diff --git a/tests/integration/idmap.bats b/tests/integration/idmap.bats
index 375191bf..5bd554ca 100644
--- a/tests/integration/idmap.bats
+++ b/tests/integration/idmap.bats
@@ -72,6 +72,14 @@ function teardown() {
 	[[ "$output" == *"shared"* ]]
 }
 
+@test "idmap mount with relative path" {
+	update_config ' .mounts |= map((select(.source == "source-1/") | .destination = "tmp/mount-1") // .)'
+
+	runc run test_debian
+	[ "$status" -eq 0 ]
+	[[ "$output" == *"=0=0="* ]]
+}
+
 @test "idmap mount with bind mount" {
 	update_config '   .mounts += [
 					{