From 9f5ee7e328284deaa13d3a21e21713e37e00ebc5 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Wed, 30 Oct 2024 19:13:13 +1100 Subject: [PATCH] tests: add test for 'weird' external namespace joining Signed-off-by: Aleksa Sarai --- tests/integration/userns.bats | 61 ++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/tests/integration/userns.bats b/tests/integration/userns.bats index 78583ba4d45..52bb5f6a9c2 100644 --- a/tests/integration/userns.bats +++ b/tests/integration/userns.bats @@ -29,7 +29,7 @@ function teardown() { if [ -v to_umount_list ]; then while read -r mount_path; do umount -l "$mount_path" || : - rm -f "$mount_path" + rm -rf "$mount_path" done <"$to_umount_list" rm -f "$to_umount_list" unset to_umount_list @@ -184,3 +184,62 @@ function teardown() { grep -E '^\s+0\s+'$EUID'\s+1$' <<<"$output" fi } + +# +@test "userns join external namespaces [wrong userns owner]" { + requires root + + # Create an external user namespace for us to join (we can't mount from + # inside the user namespace so we need to background it to do the mount + # from the host). + userns_path="$(mktemp "$BATS_RUN_TMPDIR/userns.XXXXXX")" + unshare -U -- sleep 3m & + userns_pid="$!" + # Synchronise with the container startup... + cat "/proc/$userns_pid/uid_map" "/proc/$userns_pid/gid_map" >&2 + # Configure the mapping to match the rootfs mapping. + echo "0 100000 65534" >"/proc/$userns_pid/uid_map" + echo "0 200000 65534" >"/proc/$userns_pid/gid_map" + # Stash the nsfsfd. + mount --bind "/proc/$userns_pid/ns/user" "$userns_path" + echo "$userns_path" >>"$to_umount_list" + # Kill the helper. + kill -9 "$userns_pid" + + # Configure our container to attach to the external userns. + update_config '.linux.namespaces |= map(if .type == "user" then (.path = "'"$userns_path"'") else . end) + | del(.linux.uidMappings) + | del(.linux.gidMappings)' + + # Also create a network namespace that *is not owned* by the above userns. + # NOTE: Having no permissions in a namespaces makes it necessary to modify + # the config so that we don't get mount errors (for reference: no netns + # permissions == no sysfs mounts, no pidns permissoins == no procfs mounts, + # no utsns permissions == no sethostname(2), no ipc permissions == no + # mqueue mounts, etc). + netns_path="$(mktemp "$BATS_RUN_TMPDIR/netns.XXXXXX")" + unshare -i -- mount --bind "/proc/self/ns/net" "$netns_path" + echo "$netns_path" >>"$to_umount_list" + # Configure our container to attach to the external netns. + update_config '.linux.namespaces |= map(if .type == "network" then (.path = "'"$netns_path"'") else . end)' + + # Convert sysfs mounts to a bind-mount from the host, to avoid the + # permission issues due to the netns setup we have. + update_config '.mounts |= map((select(.type == "sysfs") | { "source": "/sys", "destination": .destination, "type": "bind", "options": ["rbind"] }) // .)' + + # Create a detached container to verify the namespaces are correct. + update_config '.process.args = ["sleep", "infinity"]' + runc --debug run -d --console-socket "$CONSOLE_SOCKET" ctr + [ "$status" -eq 0 ] + + userns_id="user:[$(stat -c "%i" "$userns_path")]" + netns_id="net:[$(stat -c "%i" "$netns_path")]" + + runc exec ctr readlink /proc/self/ns/user + [ "$status" -eq 0 ] + [[ "$output" == "$userns_id" ]] + + runc exec ctr readlink /proc/self/ns/net + [ "$status" -eq 0 ] + [[ "$output" == "$netns_id" ]] +}