github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/tests/integration/mounts.bats (about) 1 #!/usr/bin/env bats 2 3 load helpers 4 5 function setup() { 6 setup_busybox 7 } 8 9 function teardown() { 10 teardown_bundle 11 } 12 13 # https://github.com/opencontainers/runc/security/advisories/GHSA-m8cg-xc2p-r3fc 14 # 15 # This needs to be placed at the top of the bats file to work around 16 # a shellcheck bug. See <https://github.com/koalaman/shellcheck/issues/2873>. 17 function test_ro_cgroup_mount() { 18 local lines status 19 # shellcheck disable=SC2016 20 update_config '.process.args |= ["sh", "-euc", "for f in `grep /sys/fs/cgroup /proc/mounts | awk \"{print \\\\$2}\"| uniq`; do test -e $f && grep -w $f /proc/mounts | tail -n1; done"]' 21 runc run test_busybox 22 [ "$status" -eq 0 ] 23 [ "${#lines[@]}" -ne 0 ] 24 for line in "${lines[@]}"; do [[ "${line}" == *'ro,'* ]]; done 25 } 26 27 # Parse an "optstring" of the form foo,bar into $is_foo and $is_bar variables. 28 # Usage: parse_optstring foo,bar foo bar baz 29 function parse_optstring() { 30 optstring="$1" 31 shift 32 33 for flag in "$@"; do 34 is_set= 35 if grep -wq "$flag" <<<"$optstring"; then 36 is_set=1 37 fi 38 eval "is_$flag=$is_set" 39 done 40 } 41 42 function config_add_bind_mount() { 43 src="$1" 44 dst="$2" 45 parse_optstring "${3:-}" rbind idmap 46 47 bindtype=bind 48 if [ -n "$is_rbind" ]; then 49 bindtype=rbind 50 fi 51 52 mappings="" 53 if [ -n "$is_idmap" ]; then 54 mappings=' 55 "uidMappings": [{"containerID": 0, "hostID": 100000, "size": 65536}], 56 "gidMappings": [{"containerID": 0, "hostID": 100000, "size": 65536}], 57 ' 58 fi 59 60 update_config '.mounts += [{ 61 "source": "'"$src"'", 62 "destination": "'"$dst"'", 63 "type": "bind", 64 '"$mappings"' 65 "options": [ "'"$bindtype"'", "rprivate" ] 66 }]' 67 } 68 69 # This needs to be placed at the top of the bats file to work around 70 # a shellcheck bug. See <https://github.com/koalaman/shellcheck/issues/2873>. 71 function test_mount_order() { 72 parse_optstring "${1:-}" userns idmap 73 74 if [ -n "$is_userns" ]; then 75 requires root 76 77 update_config '.linux.namespaces += [{"type": "user"}] 78 | .linux.uidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}] 79 | .linux.gidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}]' 80 remap_rootfs 81 fi 82 83 ctr_src_opts="rbind" 84 if [ -n "$is_idmap" ]; then 85 requires root 86 requires_kernel 5.12 87 requires_idmap_fs . 88 89 ctr_src_opts+=",idmap" 90 fi 91 92 mkdir -p rootfs/{mnt,final} 93 # Create a set of directories we can create a mount tree with. 94 for subdir in a/x b/y c/z; do 95 dir="bind-src/$subdir" 96 mkdir -p "$dir" 97 echo "$subdir" >"$dir/file" 98 # Add a symlink to make sure 99 topdir="$(dirname "$subdir")" 100 ln -s "$topdir" "bind-src/sym-$topdir" 101 done 102 # In userns tests, make sure that the source directory cannot be accessed, 103 # to make sure we're exercising the bind-mount source fd logic. 104 chmod o-rwx bind-src 105 106 rootfs="$(pwd)/rootfs" 107 rm -rf rootfs/mnt 108 mkdir rootfs/mnt 109 110 # Create a bind-mount tree. 111 config_add_bind_mount "$PWD/bind-src/a" "/mnt" 112 config_add_bind_mount "$PWD/bind-src/sym-b" "/mnt/x" 113 config_add_bind_mount "$PWD/bind-src/c" "/mnt/x/y" 114 config_add_bind_mount "$PWD/bind-src/sym-a" "/mnt/x/y/z" 115 # Create a recursive bind-mount that uses part of the current tree in the 116 # container. 117 config_add_bind_mount "$rootfs/mnt/x" "$rootfs/mnt/x/y/z/x" "$ctr_src_opts" 118 config_add_bind_mount "$rootfs/mnt/x/y" "$rootfs/mnt/x/y/z" "$ctr_src_opts" 119 # Finally, bind-mount the whole thing on top of /final. 120 config_add_bind_mount "$rootfs/mnt" "$rootfs/final" "$ctr_src_opts" 121 122 # Check that the entire tree was copied and the mounts were done in the 123 # expected order. 124 update_config '.process.args = ["cat", "/final/x/y/z/z/x/y/z/x/file"]' 125 runc run test_busybox 126 [ "$status" -eq 0 ] 127 [[ "$output" == *"a/x"* ]] # the final "file" was from a/x. 128 } 129 130 # https://github.com/opencontainers/runc/issues/3991 131 @test "runc run [tmpcopyup]" { 132 mkdir -p rootfs/dir1/dir2 133 chmod 777 rootfs/dir1/dir2 134 update_config ' .mounts += [{ 135 source: "tmpfs", 136 destination: "/dir1", 137 type: "tmpfs", 138 options: ["tmpcopyup"] 139 }] 140 | .process.args |= ["ls", "-ld", "/dir1/dir2"]' 141 142 umask 022 143 runc run test_busybox 144 [ "$status" -eq 0 ] 145 [[ "${lines[0]}" == *'drwxrwxrwx'* ]] 146 } 147 148 @test "runc run [bind mount]" { 149 update_config ' .mounts += [{ 150 source: ".", 151 destination: "/tmp/bind", 152 options: ["bind"] 153 }] 154 | .process.args |= ["ls", "/tmp/bind/config.json"]' 155 156 runc run test_busybox 157 [ "$status" -eq 0 ] 158 [[ "${lines[0]}" == *'/tmp/bind/config.json'* ]] 159 } 160 161 # https://github.com/opencontainers/runc/issues/2246 162 @test "runc run [ro tmpfs mount]" { 163 update_config ' .mounts += [{ 164 source: "tmpfs", 165 destination: "/mnt", 166 type: "tmpfs", 167 options: ["ro", "nodev", "nosuid", "mode=755"] 168 }] 169 | .process.args |= ["grep", "^tmpfs /mnt", "/proc/mounts"]' 170 171 runc run test_busybox 172 [ "$status" -eq 0 ] 173 [[ "${lines[0]}" == *'ro,'* ]] 174 } 175 176 # https://github.com/opencontainers/runc/issues/3248 177 @test "runc run [ro /dev mount]" { 178 update_config ' .mounts |= map((select(.destination == "/dev") | .options += ["ro"]) // .) 179 | .process.args |= ["grep", "^tmpfs /dev", "/proc/mounts"]' 180 181 runc run test_busybox 182 [ "$status" -eq 0 ] 183 [[ "${lines[0]}" == *'ro,'* ]] 184 } 185 186 # https://github.com/opencontainers/runc/issues/2683 187 @test "runc run [tmpfs mount with absolute symlink]" { 188 # in container, /conf -> /real/conf 189 mkdir -p rootfs/real/conf 190 ln -s /real/conf rootfs/conf 191 update_config ' .mounts += [{ 192 type: "tmpfs", 193 source: "tmpfs", 194 destination: "/conf/stack", 195 options: ["ro", "nodev", "nosuid"] 196 }] 197 | .process.args |= ["true"]' 198 runc run test_busybox 199 [ "$status" -eq 0 ] 200 } 201 202 @test "runc run [ro /sys/fs/cgroup mounts]" { 203 # Without cgroup namespace. 204 update_config '.linux.namespaces -= [{"type": "cgroup"}]' 205 test_ro_cgroup_mount 206 } 207 208 @test "runc run [ro /sys/fs/cgroup mounts + cgroupns]" { 209 requires cgroupns 210 # With cgroup namespace. 211 update_config '.linux.namespaces |= if index({"type": "cgroup"}) then . else . + [{"type": "cgroup"}] end' 212 test_ro_cgroup_mount 213 } 214 215 @test "runc run [mount order, container bind-mount source]" { 216 test_mount_order 217 } 218 219 @test "runc run [mount order, container bind-mount source] (userns)" { 220 test_mount_order userns 221 } 222 223 @test "runc run [mount order, container idmap source]" { 224 test_mount_order idmap 225 } 226 227 @test "runc run [mount order, container idmap source] (userns)" { 228 test_mount_order userns,idmap 229 }