Skip to content

Commit 6f2355f

Browse files
committed
Fallback to bind mount for sysfs in user namespaces
Signed-off-by: HirazawaUi <695097494plus@gmail.com>
1 parent 59a5ff1 commit 6f2355f

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

libcontainer/rootfs_linux.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,19 @@ func mountToRootfs(c *mountConfig, m mountEntry) error {
622622
// "proc" and "sys" mounts need special handling (without resolving the
623623
// destination) to avoid attacks.
624624
m.dstFile = dstFile
625-
return m.mountPropagate(rootfs, "")
625+
err = m.mountPropagate(rootfs, "")
626+
if err != nil && m.Device == "sysfs" && errors.Is(err, unix.EPERM) {
627+
logrus.Debugf("cannot mount sysfs with properties, fallback to bind mount: %v", err)
628+
bindM := &configs.Mount{
629+
Device: "bind",
630+
Source: "/sys",
631+
Destination: m.Destination,
632+
Flags: unix.MS_BIND | unix.MS_REC | m.Flags,
633+
PropagationFlags: m.PropagationFlags,
634+
}
635+
return mountToRootfs(c, mountEntry{Mount: bindM})
636+
}
637+
return err
626638
}
627639

628640
mountLabel := c.label

tests/integration/userns.bats

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,3 +280,27 @@ function teardown() {
280280
# is deleted during the namespace cleanup.
281281
run ! ip link del dummy0
282282
}
283+
284+
@test "userns with host network: sysfs mount should fall back to bind mount" {
285+
# This test runs in a user namespace (setup by default for this file).
286+
# It also uses the host network namespace.
287+
288+
# Remove network namespace to use host network.
289+
update_config '.linux.namespaces |= map(select(.type != "network"))'
290+
291+
# The default spec for rootless on cgroup v2 systems may use a bind
292+
# mount for /sys. To test the sysfs mount fallback, we explicitly
293+
# force a sysfs-type mount. In a user namespace, this is not
294+
# permitted and should fail with EPERM. runc should then fall back
295+
# to a bind mount.
296+
update_config '.mounts |= map(if .destination == "/sys" then .type = "sysfs" | .source = "sysfs" | .options = ["nosuid", "noexec", "nodev", "ro"] else . end)'
297+
298+
# We check if /sys/class/net exists to verify that /sys is mounted
299+
# correctly after the fallback.
300+
update_config '.process.args = ["ls", "/sys/class/net"]'
301+
302+
runc run test_userns_sysfs_fallback
303+
[ "$status" -eq 0 ]
304+
# Check for loopback interface, which should always be present on the host.
305+
[[ "$output" == *"lo"* ]]
306+
}

0 commit comments

Comments
 (0)