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 <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin committed 2026-10-17 10:30:39 -07:00
1 parent c107d70ea5
commit 66e3067ea6
4 files changed
+42

No files matched your search

+7
View File
@@ -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.
@@ -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
}
+11
View File
@@ -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"
}
+14
View File
@@ -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"
}