From fa93c8b05b323187d0c5e3bdb3622c23c3abcfff Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Fri, 1 Dec 2023 17:08:38 +1100 Subject: [PATCH] tests: mounts: add some tests to check mount ordering Our previous implementation of idmapped mounts and bind-mount sources would open all of the source paths before we did any mounts, meaning that mounts using sources from inside the container rootfs would not be correct. This has been fixed with the new on-demand system, and so add some regression tests. Signed-off-by: Aleksa Sarai --- tests/integration/mounts.bats | 119 ++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/tests/integration/mounts.bats b/tests/integration/mounts.bats index a4d997ca765..5dafb655c92 100644 --- a/tests/integration/mounts.bats +++ b/tests/integration/mounts.bats @@ -24,6 +24,109 @@ function test_ro_cgroup_mount() { for line in "${lines[@]}"; do [[ "${line}" == *'ro,'* ]]; done } +# Parse an "optstring" of the form foo,bar into $is_foo and $is_bar variables. +# Usage: parse_optstring foo,bar foo bar baz +function parse_optstring() { + optstring="$1" + shift + + for flag in "$@"; do + is_set= + if grep -wq "$flag" <<<"$optstring"; then + is_set=1 + fi + eval "is_$flag=$is_set" + done +} + +function config_add_bind_mount() { + src="$1" + dst="$2" + parse_optstring "${3:-}" rbind idmap + + bindtype=bind + if [ -n "$is_rbind" ]; then + bindtype=rbind + fi + + mappings="" + if [ -n "$is_idmap" ]; then + mappings=' + "uidMappings": [{"containerID": 0, "hostID": 100000, "size": 65536}], + "gidMappings": [{"containerID": 0, "hostID": 100000, "size": 65536}], + ' + fi + + update_config '.mounts += [{ + "source": "'"$src"'", + "destination": "'"$dst"'", + "type": "bind", + '"$mappings"' + "options": [ "'"$bindtype"'", "rprivate" ] + }]' +} + +# This needs to be placed at the top of the bats file to work around +# a shellcheck bug. See . +function test_mount_order() { + parse_optstring "${1:-}" userns idmap + + if [ -n "$is_userns" ]; then + requires root + + update_config '.linux.namespaces += [{"type": "user"}] + | .linux.uidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}] + | .linux.gidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}]' + remap_rootfs + fi + + ctr_src_opts="rbind" + if [ -n "$is_idmap" ]; then + requires root + requires_kernel 5.12 + requires_idmap_fs . + + ctr_src_opts+=",idmap" + fi + + mkdir -p rootfs/{mnt,final} + # Create a set of directories we can create a mount tree with. + for subdir in a/x b/y c/z; do + dir="bind-src/$subdir" + mkdir -p "$dir" + echo "$subdir" >"$dir/file" + # Add a symlink to make sure + topdir="$(dirname "$subdir")" + ln -s "$topdir" "bind-src/sym-$topdir" + done + # In userns tests, make sure that the source directory cannot be accessed, + # to make sure we're exercising the bind-mount source fd logic. + chmod o-rwx bind-src + + rootfs="$(pwd)/rootfs" + rm -rf rootfs/mnt + mkdir rootfs/mnt + + # Create a bind-mount tree. + config_add_bind_mount "$PWD/bind-src/a" "/mnt" + config_add_bind_mount "$PWD/bind-src/sym-b" "/mnt/x" + config_add_bind_mount "$PWD/bind-src/c" "/mnt/x/y" + config_add_bind_mount "$PWD/bind-src/sym-a" "/mnt/x/y/z" + # Create a recursive bind-mount that uses part of the current tree in the + # container. + config_add_bind_mount "$rootfs/mnt/x" "$rootfs/mnt/x/y/z/x" "$ctr_src_opts" + config_add_bind_mount "$rootfs/mnt/x/y" "$rootfs/mnt/x/y/z" "$ctr_src_opts" + # Finally, bind-mount the whole thing on top of /final. + config_add_bind_mount "$rootfs/mnt" "$rootfs/final" "$ctr_src_opts" + + # Check that the entire tree was copied and the mounts were done in the + # expected order. + update_config '.process.args = ["cat", "/final/x/y/z/z/x/y/z/x/file"]' + runc run test_busybox + [ "$status" -eq 0 ] + [[ "$output" == *"a/x"* ]] # the final "file" was from a/x. +} + # https://github.com/opencontainers/runc/issues/3991 @test "runc run [tmpcopyup]" { mkdir -p rootfs/dir1/dir2 @@ -108,3 +211,19 @@ function test_ro_cgroup_mount() { update_config '.linux.namespaces |= if index({"type": "cgroup"}) then . else . + [{"type": "cgroup"}] end' test_ro_cgroup_mount } + +@test "runc run [mount order, container bind-mount source]" { + test_mount_order +} + +@test "runc run [mount order, container bind-mount source] (userns)" { + test_mount_order userns +} + +@test "runc run [mount order, container idmap source]" { + test_mount_order idmap +} + +@test "runc run [mount order, container idmap source] (userns)" { + test_mount_order userns,idmap +}