From 66e3067ea69b5a6f88cab3272124153ccecfa8dd Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 9 Oct 2026 10:47:38 -0700 Subject: [PATCH] libct/cfg/validate: require mount ns for no-pivot, rootfsPropagation When the container does not have its own mount namespace, using --no-pivot results in msMoveRoot being run in the host mount namespace. It unmounts host's procfs and sysfs mounts, and then moves the container rootfs on top of the host's /, effectively breaking the host. Similarly, rootfs propagation is applied to / and to the parent mount of the container rootfs. Without a private mount namespace, this changes the propagation of host mounts. Disallow both configurations. Add integration tests (the --no-pivot one is marked as unsafe, since without the fix it breaks the host). Signed-off-by: Kir Kolyshkin --- CHANGELOG.md | 7 +++++++ libcontainer/configs/validate/validator.go | 10 ++++++++++ tests/integration/mounts_propagation.bats | 11 +++++++++++ tests/integration/no_pivot.bats | 14 ++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5149d7ff..6bd67d448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 they are always empty since the removal of veth network strategy in runc 1.0.0-rc6. (#5523) +### Changed ### +- A container configuration which uses `--no-pivot` or sets + `linux.rootfsPropagation`, but does not have its own mount namespace, is now + refused. Previously, `--no-pivot` resulted in host's `/proc` and `/sys` being + unmounted, and `rootfsPropagation` changed the propagation of host mounts. + (#5535) + ## [1.6.0-rc.1] - 2026-10-06 > Lo bueno, si breve, dos veces bueno. diff --git a/libcontainer/configs/validate/validator.go b/libcontainer/configs/validate/validator.go index e7d95436c..70097f5bb 100644 --- a/libcontainer/configs/validate/validator.go +++ b/libcontainer/configs/validate/validator.go @@ -148,6 +148,16 @@ func mountns(config *configs.Config) error { return fmt.Errorf("unable to make %s read-only without a private MNT namespace", m.Destination) } } + // Without pivot_root, the container rootfs is moved on top of / + // (and host's procfs and sysfs mounts are unmounted). + if config.NoPivotRoot { + return errors.New("unable to use no-pivot without a private MNT namespace") + } + // Rootfs propagation is applied to / and to the parent mount of + // the container rootfs. + if config.RootPropagation != 0 { + return errors.New("unable to set rootfs propagation without a private MNT namespace") + } return nil } diff --git a/tests/integration/mounts_propagation.bats b/tests/integration/mounts_propagation.bats index 536a50b36..1bcdeedbd 100644 --- a/tests/integration/mounts_propagation.bats +++ b/tests/integration/mounts_propagation.bats @@ -19,3 +19,14 @@ function teardown() { run -0 runc run test_shared_rootfs assert_output "shared" } + +@test "runc run [rootfsPropagation, host mount ns] must fail" { + update_config ' .linux.rootfsPropagation = "rslave" + | .linux.namespaces -= [{"type": "mount"}] + | .linux.maskedPaths = [] + | .linux.readonlyPaths = [] + | .root.readonly = false' + + run -1 runc run test_host_mntns + assert_output --partial "unable to set rootfs propagation without a private MNT namespace" +} diff --git a/tests/integration/no_pivot.bats b/tests/integration/no_pivot.bats index f82045b1f..0a0eb1ecc 100644 --- a/tests/integration/no_pivot.bats +++ b/tests/integration/no_pivot.bats @@ -20,3 +20,17 @@ function teardown() { run -1 runc run --no-pivot test_no_pivot assert_output --partial "mount: permission denied" } + +@test "runc run --no-pivot [host mount ns] must fail" { + # Unsafe because, if the bug is present, host's /proc and /sys + # are unmounted, breaking the host. + requires root unsafe + + update_config ' .linux.namespaces -= [{"type": "mount"}] + | .linux.maskedPaths = [] + | .linux.readonlyPaths = [] + | .root.readonly = false' + + run -1 runc run --no-pivot test_no_pivot + assert_output --partial "unable to use no-pivot without a private MNT namespace" +}