#!/usr/bin/env bats load helpers function setup() { OVERFLOW_UID="$(cat /proc/sys/kernel/overflowuid)" OVERFLOW_GID="$(cat /proc/sys/kernel/overflowgid)" requires root requires_kernel 5.12 setup_debian requires_idmap_fs . # Prepare source folders for mounts. mkdir -p source-{1,2,multi{1,2,3}}/ touch source-{1,2,multi{1,2,3}}/foo.txt touch source-multi{1,2,3}/{bar,baz}.txt # Change the owners for everything other than source-1. chown 1:1 source-2/foo.txt # A source with multiple users owning files. chown 100:211 source-multi1/foo.txt chown 101:222 source-multi1/bar.txt chown 102:233 source-multi1/baz.txt # Same gids as multi1, different uids. chown 200:211 source-multi2/foo.txt chown 201:222 source-multi2/bar.txt chown 202:233 source-multi2/baz.txt # Even more users -- 1000 uids, 500 gids. chown 5000528:6000491 source-multi3/foo.txt chown 5000133:6000337 source-multi3/bar.txt chown 5000999:6000444 source-multi3/baz.txt # Add a symlink-containing source. ln -s source-multi1 source-multi1-symlink # Add some top-level files in the mount tree. mkdir -p mnt-subtree/multi{1,2} touch mnt-subtree/{foo,bar,baz}.txt chown 100:211 mnt-subtree/foo.txt chown 200:222 mnt-subtree/bar.txt chown 300:233 mnt-subtree/baz.txt mounts_file="$PWD/.all-mounts" echo -n >"$mounts_file" } function teardown() { if [ -v mounts_file ]; then xargs -n 1 -a "$mounts_file" -- umount -l rm -f "$mounts_file" fi teardown_bundle } function setup_host_bind_mount() { src="$1" dst="$2" mount --bind "$src" "$dst" echo "$dst" >>"$mounts_file" } function setup_idmap_userns() { update_config '.linux.namespaces += [{"type": "user"}] | .linux.uidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}] | .linux.gidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}]' remap_rootfs } function setup_bind_mount() { mountname="${1:-1}" update_config '.mounts += [ { "source": "source-'"$mountname"'/", "destination": "/tmp/bind-mount-'"$mountname"'", "options": ["bind"] } ]' } function setup_idmap_single_mount() { uidmap="$1" # ctr:host:size gidmap="$2" # ctr:host:size mountname="$3" destname="${4:-$mountname}" read -r uid_containerID uid_hostID uid_size <<<"$(tr : ' ' <<<"$uidmap")" read -r gid_containerID gid_hostID gid_size <<<"$(tr : ' ' <<<"$gidmap")" update_config '.mounts += [ { "source": "source-'"$mountname"'/", "destination": "/tmp/mount-'"$destname"'", "options": ["bind"], "uidMappings": [{"containerID": '"$uid_containerID"', "hostID": '"$uid_hostID"', "size": '"$uid_size"'}], "gidMappings": [{"containerID": '"$gid_containerID"', "hostID": '"$gid_hostID"', "size": '"$gid_size"'}] } ]' } function setup_idmap_basic_mount() { mountname="${1:-1}" destname="${2:-}" setup_idmap_single_mount 0:100000:65536 0:100000:65536 "$mountname" "$destname" } @test "Check mount source fds are cleaned up with idmapped mounts [userns]" { setup_idmap_userns for i in {1..10}; do setup_idmap_basic_mount 1 "1$i" setup_idmap_basic_mount 2 "2$i" done update_config '.process.args = ["sh", "-c", "stat -c =%u=%g= /tmp/mount-11/foo.txt"]' update_config '.process.rlimits = [{ "type": "RLIMIT_NOFILE", "soft": 20, "hard": 20 }]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=0=0="* ]] } @test "simple idmap mount [userns]" { setup_idmap_userns setup_idmap_basic_mount update_config '.process.args = ["sh", "-c", "stat -c =%u=%g= /tmp/mount-1/foo.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=0=0="* ]] } @test "simple idmap mount [no userns]" { setup_idmap_basic_mount update_config '.process.args = ["sh", "-c", "stat -c =%u=%g= /tmp/mount-1/foo.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=100000=100000="* ]] } @test "write to an idmap mount [userns]" { setup_idmap_userns setup_idmap_basic_mount update_config '.process.args = ["sh", "-c", "touch /tmp/mount-1/bar && stat -c =%u=%g= /tmp/mount-1/bar"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=0=0="* ]] } @test "write to an idmap mount [no userns]" { setup_idmap_basic_mount update_config '.process.args = ["sh", "-c", "touch /tmp/mount-1/bar && stat -c =%u=%g= /tmp/mount-1/bar"]' runc run test_debian # The write must fail because the user is unmapped. [ "$status" -ne 0 ] [[ "$output" == *"Value too large for defined data type"* ]] # ERANGE } @test "idmap mount with propagation flag [userns]" { setup_idmap_userns setup_idmap_basic_mount update_config '.process.args = ["sh", "-c", "findmnt -o PROPAGATION /tmp/mount-1"]' # Add the shared option to the idmap mount. update_config '.mounts |= map((select(.source == "source-1/") | .options += ["shared"]) // .)' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"shared"* ]] } @test "idmap mount with relative path [userns]" { setup_idmap_userns setup_idmap_basic_mount update_config '.process.args = ["sh", "-c", "stat -c =%u=%g= /tmp/mount-1/foo.txt"]' # Switch the mount to have a relative mount destination. update_config '.mounts |= map((select(.source == "source-1/") | .destination = "tmp/mount-1") // .)' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=0=0="* ]] } @test "idmap mount with bind mount [userns]" { setup_idmap_userns setup_idmap_basic_mount setup_bind_mount update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/{,bind-}mount-1/foo.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-1/foo.txt:0=0="* ]] [[ "$output" == *"=/tmp/bind-mount-1/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] } @test "idmap mount with bind mount [no userns]" { setup_idmap_basic_mount setup_bind_mount update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/{,bind-}mount-1/foo.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-1/foo.txt:100000=100000="* ]] [[ "$output" == *"=/tmp/bind-mount-1/foo.txt:0=0="* ]] } @test "two idmap mounts (same mapping) with two bind mounts [userns]" { setup_idmap_userns setup_idmap_basic_mount 1 setup_bind_mount 1 setup_bind_mount 2 setup_idmap_basic_mount 2 update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-[12]/foo.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-1/foo.txt:0=0="* ]] [[ "$output" == *"=/tmp/mount-2/foo.txt:1=1="* ]] } @test "same idmap mount (different mappings) [userns]" { setup_idmap_userns # Mount the same directory with different mappings. Make sure we also use # different mappings for uids and gids. setup_idmap_single_mount 100:100000:100 200:100000:100 multi1 setup_idmap_single_mount 100:101000:100 200:102000:100 multi1 multi1-alt setup_idmap_single_mount 100:102000:100 200:103000:100 multi1-symlink multi1-alt-sym update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi1{,-alt{,-sym}}/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-multi1/foo.txt:0=11="* ]] [[ "$output" == *"=/tmp/mount-multi1/bar.txt:1=22="* ]] [[ "$output" == *"=/tmp/mount-multi1/baz.txt:2=33="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt/foo.txt:1000=2011="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt/bar.txt:1001=2022="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt/baz.txt:1002=2033="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt-sym/foo.txt:2000=3011="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt-sym/bar.txt:2001=3022="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt-sym/baz.txt:2002=3033="* ]] } @test "same idmap mount (different mappings) [no userns]" { # Mount the same directory with different mappings. Make sure we also use # different mappings for uids and gids. setup_idmap_single_mount 100:100000:100 200:100000:100 multi1 setup_idmap_single_mount 100:101000:100 200:102000:100 multi1 multi1-alt setup_idmap_single_mount 100:102000:100 200:103000:100 multi1-symlink multi1-alt-sym update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi1{,-alt{,-sym}}/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-multi1/foo.txt:100000=100011="* ]] [[ "$output" == *"=/tmp/mount-multi1/bar.txt:100001=100022="* ]] [[ "$output" == *"=/tmp/mount-multi1/baz.txt:100002=100033="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt/foo.txt:101000=102011="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt/bar.txt:101001=102022="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt/baz.txt:101002=102033="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt-sym/foo.txt:102000=103011="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt-sym/bar.txt:102001=103022="* ]] [[ "$output" == *"=/tmp/mount-multi1-alt-sym/baz.txt:102002=103033="* ]] } @test "multiple idmap mounts (different mappings) [userns]" { setup_idmap_userns # Make sure we use different mappings for uids and gids. setup_idmap_single_mount 100:101100:3 200:101900:50 multi1 setup_idmap_single_mount 200:102200:3 200:102900:100 multi2 setup_idmap_single_mount 5000000:103000:1000 6000000:103000:500 multi3 update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi[123]/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-multi1/foo.txt:1100=1911="* ]] [[ "$output" == *"=/tmp/mount-multi1/bar.txt:1101=1922="* ]] [[ "$output" == *"=/tmp/mount-multi1/baz.txt:1102=1933="* ]] [[ "$output" == *"=/tmp/mount-multi2/foo.txt:2200=2911="* ]] [[ "$output" == *"=/tmp/mount-multi2/bar.txt:2201=2922="* ]] [[ "$output" == *"=/tmp/mount-multi2/baz.txt:2202=2933="* ]] [[ "$output" == *"=/tmp/mount-multi3/foo.txt:3528=3491="* ]] [[ "$output" == *"=/tmp/mount-multi3/bar.txt:3133=3337="* ]] [[ "$output" == *"=/tmp/mount-multi3/baz.txt:3999=3444="* ]] } @test "multiple idmap mounts (different mappings) [no userns]" { # Make sure we use different mappings for uids and gids. setup_idmap_single_mount 100:1100:3 200:1900:50 multi1 setup_idmap_single_mount 200:2200:3 200:2900:100 multi2 setup_idmap_single_mount 5000000:3000:1000 6000000:3000:500 multi3 update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi[123]/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-multi1/foo.txt:1100=1911="* ]] [[ "$output" == *"=/tmp/mount-multi1/bar.txt:1101=1922="* ]] [[ "$output" == *"=/tmp/mount-multi1/baz.txt:1102=1933="* ]] [[ "$output" == *"=/tmp/mount-multi2/foo.txt:2200=2911="* ]] [[ "$output" == *"=/tmp/mount-multi2/bar.txt:2201=2922="* ]] [[ "$output" == *"=/tmp/mount-multi2/baz.txt:2202=2933="* ]] [[ "$output" == *"=/tmp/mount-multi3/foo.txt:3528=3491="* ]] [[ "$output" == *"=/tmp/mount-multi3/bar.txt:3133=3337="* ]] [[ "$output" == *"=/tmp/mount-multi3/baz.txt:3999=3444="* ]] } @test "idmap mount (complicated mapping) [userns]" { setup_idmap_userns update_config '.mounts += [ { "source": "source-multi1/", "destination": "/tmp/mount-multi1", "options": ["bind"], "uidMappings": [ {"containerID": 100, "hostID": 101000, "size": 1}, {"containerID": 101, "hostID": 102000, "size": 1}, {"containerID": 102, "hostID": 103000, "size": 1} ], "gidMappings": [ {"containerID": 210, "hostID": 101100, "size": 10}, {"containerID": 220, "hostID": 102200, "size": 10}, {"containerID": 230, "hostID": 103300, "size": 10} ] } ]' update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi1/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-multi1/foo.txt:1000=1101="* ]] [[ "$output" == *"=/tmp/mount-multi1/bar.txt:2000=2202="* ]] [[ "$output" == *"=/tmp/mount-multi1/baz.txt:3000=3303="* ]] } @test "idmap mount (complicated mapping) [no userns]" { update_config '.mounts += [ { "source": "source-multi1/", "destination": "/tmp/mount-multi1", "options": ["bind"], "uidMappings": [ {"containerID": 100, "hostID": 1000, "size": 1}, {"containerID": 101, "hostID": 2000, "size": 1}, {"containerID": 102, "hostID": 3000, "size": 1} ], "gidMappings": [ {"containerID": 210, "hostID": 1100, "size": 10}, {"containerID": 220, "hostID": 2200, "size": 10}, {"containerID": 230, "hostID": 3300, "size": 10} ] } ]' update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi1/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-multi1/foo.txt:1000=1101="* ]] [[ "$output" == *"=/tmp/mount-multi1/bar.txt:2000=2202="* ]] [[ "$output" == *"=/tmp/mount-multi1/baz.txt:3000=3303="* ]] } @test "idmap mount (non-recursive idmap) [userns]" { setup_idmap_userns setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1" setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2" update_config '.mounts += [ { "source": "mnt-subtree/", "destination": "/tmp/mount-tree", "options": ["rbind"], "uidMappings": [ {"containerID": 100, "hostID": 101000, "size": 3}, {"containerID": 200, "hostID": 102000, "size": 3}, {"containerID": 300, "hostID": 103000, "size": 3} ], "gidMappings": [ {"containerID": 210, "hostID": 101100, "size": 10}, {"containerID": 220, "hostID": 102200, "size": 10}, {"containerID": 230, "hostID": 103300, "size": 10} ] } ]' update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-tree/foo.txt:1000=1101="* ]] [[ "$output" == *"=/tmp/mount-tree/bar.txt:2000=2202="* ]] [[ "$output" == *"=/tmp/mount-tree/baz.txt:3000=3303="* ]] # Because we used "idmap", the child mounts were not remapped recursively. [[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] } @test "idmap mount (non-recursive idmap) [no userns]" { setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1" setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2" update_config '.mounts += [ { "source": "mnt-subtree/", "destination": "/tmp/mount-tree", "options": ["rbind"], "uidMappings": [ {"containerID": 100, "hostID": 101000, "size": 3}, {"containerID": 200, "hostID": 102000, "size": 3}, {"containerID": 300, "hostID": 103000, "size": 3} ], "gidMappings": [ {"containerID": 210, "hostID": 101100, "size": 10}, {"containerID": 220, "hostID": 102200, "size": 10}, {"containerID": 230, "hostID": 103300, "size": 10} ] } ]' update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-tree/foo.txt:101000=101101="* ]] [[ "$output" == *"=/tmp/mount-tree/bar.txt:102000=102202="* ]] [[ "$output" == *"=/tmp/mount-tree/baz.txt:103000=103303="* ]] # Because we used "idmap", the child mounts were not remapped recursively. [[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:100=211="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:101=222="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:102=233="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:200=211="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:201=222="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:202=233="* ]] } @test "idmap mount (idmap flag) [userns]" { setup_idmap_userns setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1" setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2" update_config '.mounts += [ { "source": "mnt-subtree/", "destination": "/tmp/mount-tree", "options": ["rbind", "idmap"], "uidMappings": [ {"containerID": 100, "hostID": 101000, "size": 3}, {"containerID": 200, "hostID": 102000, "size": 3}, {"containerID": 300, "hostID": 103000, "size": 3} ], "gidMappings": [ {"containerID": 210, "hostID": 101100, "size": 10}, {"containerID": 220, "hostID": 102200, "size": 10}, {"containerID": 230, "hostID": 103300, "size": 10} ] } ]' update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-tree/foo.txt:1000=1101="* ]] [[ "$output" == *"=/tmp/mount-tree/bar.txt:2000=2202="* ]] [[ "$output" == *"=/tmp/mount-tree/baz.txt:3000=3303="* ]] # Because we used "idmap", the child mounts were not remapped recursively. [[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] } @test "idmap mount (idmap flag) [no userns]" { setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1" setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2" update_config '.mounts += [ { "source": "mnt-subtree/", "destination": "/tmp/mount-tree", "options": ["rbind", "idmap"], "uidMappings": [ {"containerID": 100, "hostID": 101000, "size": 3}, {"containerID": 200, "hostID": 102000, "size": 3}, {"containerID": 300, "hostID": 103000, "size": 3} ], "gidMappings": [ {"containerID": 210, "hostID": 101100, "size": 10}, {"containerID": 220, "hostID": 102200, "size": 10}, {"containerID": 230, "hostID": 103300, "size": 10} ] } ]' update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-tree/foo.txt:101000=101101="* ]] [[ "$output" == *"=/tmp/mount-tree/bar.txt:102000=102202="* ]] [[ "$output" == *"=/tmp/mount-tree/baz.txt:103000=103303="* ]] # Because we used "idmap", the child mounts were not remapped recursively. [[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:100=211="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:101=222="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:102=233="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:200=211="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:201=222="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:202=233="* ]] } @test "idmap mount (ridmap flag) [userns]" { setup_idmap_userns setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1" setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2" update_config '.mounts += [ { "source": "mnt-subtree/", "destination": "/tmp/mount-tree", "options": ["rbind", "ridmap"], "uidMappings": [ {"containerID": 100, "hostID": 101000, "size": 3}, {"containerID": 200, "hostID": 102000, "size": 3}, {"containerID": 300, "hostID": 103000, "size": 3} ], "gidMappings": [ {"containerID": 210, "hostID": 101100, "size": 10}, {"containerID": 220, "hostID": 102200, "size": 10}, {"containerID": 230, "hostID": 103300, "size": 10} ] } ]' update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-tree/foo.txt:1000=1101="* ]] [[ "$output" == *"=/tmp/mount-tree/bar.txt:2000=2202="* ]] [[ "$output" == *"=/tmp/mount-tree/baz.txt:3000=3303="* ]] # The child mounts have the same mapping applied. [[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:1000=1101="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:1001=2202="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:1002=3303="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:2000=1101="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:2001=2202="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:2002=3303="* ]] } @test "idmap mount (ridmap flag) [no userns]" { setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1" setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2" update_config '.mounts += [ { "source": "mnt-subtree/", "destination": "/tmp/mount-tree", "options": ["rbind", "ridmap"], "uidMappings": [ {"containerID": 100, "hostID": 101000, "size": 3}, {"containerID": 200, "hostID": 102000, "size": 3}, {"containerID": 300, "hostID": 103000, "size": 3} ], "gidMappings": [ {"containerID": 210, "hostID": 101100, "size": 10}, {"containerID": 220, "hostID": 102200, "size": 10}, {"containerID": 230, "hostID": 103300, "size": 10} ] } ]' update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-tree/foo.txt:101000=101101="* ]] [[ "$output" == *"=/tmp/mount-tree/bar.txt:102000=102202="* ]] [[ "$output" == *"=/tmp/mount-tree/baz.txt:103000=103303="* ]] # The child mounts have the same mapping applied. [[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:101000=101101="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:101001=102202="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:101002=103303="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:102000=101101="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:102001=102202="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:102002=103303="* ]] } @test "idmap mount (idmap flag, implied mapping) [userns]" { setup_idmap_userns setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1" setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2" update_config '.mounts += [ { "source": "mnt-subtree/", "destination": "/tmp/mount-tree", "options": ["rbind", "idmap"], } ]' update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-tree/foo.txt:100=211="* ]] [[ "$output" == *"=/tmp/mount-tree/bar.txt:200=222="* ]] [[ "$output" == *"=/tmp/mount-tree/baz.txt:300=233="* ]] # Because we used "idmap", the child mounts were not remapped recursively. [[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] } @test "idmap mount (ridmap flag, implied mapping) [userns]" { setup_idmap_userns setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1" setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2" update_config '.mounts += [ { "source": "mnt-subtree/", "destination": "/tmp/mount-tree", "options": ["rbind", "ridmap"], } ]' update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-tree/foo.txt:100=211="* ]] [[ "$output" == *"=/tmp/mount-tree/bar.txt:200=222="* ]] [[ "$output" == *"=/tmp/mount-tree/baz.txt:300=233="* ]] # The child mounts have the same mapping applied. [[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:100=211="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:101=222="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:102=233="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:200=211="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:201=222="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:202=233="* ]] } @test "idmap mount (idmap flag, implied mapping, userns join) [userns]" { # Create a detached container with the id-mapping we want. cp config.json config.json.bak update_config '.linux.namespaces += [{"type": "user"}] | .linux.uidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}] | .linux.gidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}]' update_config '.process.args = ["sleep", "infinity"]' runc run -d --console-socket "$CONSOLE_SOCKET" target_userns [ "$status" -eq 0 ] # Configure our container to attach to the first container's userns. target_pid="$(__runc state target_userns | jq .pid)" update_config '.linux.namespaces |= map(if .type == "user" then (.path = "/proc/'"$target_pid"'/ns/" + .type) else . end)' update_config 'del(.linux.uidMappings) | del(.linux.gidMappings)' setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1" setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2" update_config '.mounts += [ { "source": "mnt-subtree/", "destination": "/tmp/mount-tree", "options": ["rbind", "idmap"], } ]' update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]' runc run test_debian [ "$status" -eq 0 ] [[ "$output" == *"=/tmp/mount-tree/foo.txt:100=211="* ]] [[ "$output" == *"=/tmp/mount-tree/bar.txt:200=222="* ]] [[ "$output" == *"=/tmp/mount-tree/baz.txt:300=233="* ]] # Because we used "idmap", the child mounts were not remapped recursively. [[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] [[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]] }