github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/tests/integration/idmap.bats (about)

     1  #!/usr/bin/env bats
     2  
     3  load helpers
     4  
     5  function setup() {
     6  	OVERFLOW_UID="$(cat /proc/sys/kernel/overflowuid)"
     7  	OVERFLOW_GID="$(cat /proc/sys/kernel/overflowgid)"
     8  	requires root
     9  	requires_kernel 5.12
    10  
    11  	setup_debian
    12  	requires_idmap_fs .
    13  
    14  	# Prepare source folders for mounts.
    15  	mkdir -p source-{1,2,multi{1,2,3}}/
    16  	touch source-{1,2,multi{1,2,3}}/foo.txt
    17  	touch source-multi{1,2,3}/{bar,baz}.txt
    18  
    19  	# Change the owners for everything other than source-1.
    20  	chown 1:1 source-2/foo.txt
    21  
    22  	# A source with multiple users owning files.
    23  	chown 100:211 source-multi1/foo.txt
    24  	chown 101:222 source-multi1/bar.txt
    25  	chown 102:233 source-multi1/baz.txt
    26  
    27  	# Same gids as multi1, different uids.
    28  	chown 200:211 source-multi2/foo.txt
    29  	chown 201:222 source-multi2/bar.txt
    30  	chown 202:233 source-multi2/baz.txt
    31  
    32  	# Even more users -- 1000 uids, 500 gids.
    33  	chown 5000528:6000491 source-multi3/foo.txt
    34  	chown 5000133:6000337 source-multi3/bar.txt
    35  	chown 5000999:6000444 source-multi3/baz.txt
    36  
    37  	# Add a symlink-containing source.
    38  	ln -s source-multi1 source-multi1-symlink
    39  
    40  	# Add some top-level files in the mount tree.
    41  	mkdir -p mnt-subtree/multi{1,2}
    42  	touch mnt-subtree/{foo,bar,baz}.txt
    43  	chown 100:211 mnt-subtree/foo.txt
    44  	chown 200:222 mnt-subtree/bar.txt
    45  	chown 300:233 mnt-subtree/baz.txt
    46  
    47  	mounts_file="$PWD/.all-mounts"
    48  	echo -n >"$mounts_file"
    49  }
    50  
    51  function teardown() {
    52  	if [ -v mounts_file ]; then
    53  		xargs -n 1 -a "$mounts_file" -- umount -l
    54  		rm -f "$mounts_file"
    55  	fi
    56  	teardown_bundle
    57  }
    58  
    59  function setup_host_bind_mount() {
    60  	src="$1"
    61  	dst="$2"
    62  
    63  	mount --bind "$src" "$dst"
    64  	echo "$dst" >>"$mounts_file"
    65  }
    66  
    67  function setup_idmap_userns() {
    68  	update_config '.linux.namespaces += [{"type": "user"}]
    69  		| .linux.uidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}]
    70  		| .linux.gidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}]'
    71  	remap_rootfs
    72  }
    73  
    74  function setup_bind_mount() {
    75  	mountname="${1:-1}"
    76  	update_config '.mounts += [
    77  			{
    78  				"source": "source-'"$mountname"'/",
    79  				"destination": "/tmp/bind-mount-'"$mountname"'",
    80  				"options": ["bind"]
    81  			}
    82  		]'
    83  }
    84  
    85  function setup_idmap_single_mount() {
    86  	uidmap="$1" # ctr:host:size
    87  	gidmap="$2" # ctr:host:size
    88  	mountname="$3"
    89  	destname="${4:-$mountname}"
    90  
    91  	read -r uid_containerID uid_hostID uid_size <<<"$(tr : ' ' <<<"$uidmap")"
    92  	read -r gid_containerID gid_hostID gid_size <<<"$(tr : ' ' <<<"$gidmap")"
    93  
    94  	update_config '.mounts += [
    95  			{
    96  				"source": "source-'"$mountname"'/",
    97  				"destination": "/tmp/mount-'"$destname"'",
    98  				"options": ["bind"],
    99  				"uidMappings": [{"containerID": '"$uid_containerID"', "hostID": '"$uid_hostID"', "size": '"$uid_size"'}],
   100  				"gidMappings": [{"containerID": '"$gid_containerID"', "hostID": '"$gid_hostID"', "size": '"$gid_size"'}]
   101  			}
   102  		]'
   103  }
   104  
   105  function setup_idmap_basic_mount() {
   106  	mountname="${1:-1}"
   107  	setup_idmap_single_mount 0:100000:65536 0:100000:65536 "$mountname"
   108  }
   109  
   110  @test "simple idmap mount [userns]" {
   111  	setup_idmap_userns
   112  	setup_idmap_basic_mount
   113  
   114  	update_config '.process.args = ["sh", "-c", "stat -c =%u=%g= /tmp/mount-1/foo.txt"]'
   115  
   116  	runc run test_debian
   117  	[ "$status" -eq 0 ]
   118  	[[ "$output" == *"=0=0="* ]]
   119  }
   120  
   121  @test "simple idmap mount [no userns]" {
   122  	setup_idmap_basic_mount
   123  
   124  	update_config '.process.args = ["sh", "-c", "stat -c =%u=%g= /tmp/mount-1/foo.txt"]'
   125  
   126  	runc run test_debian
   127  	[ "$status" -eq 0 ]
   128  	[[ "$output" == *"=100000=100000="* ]]
   129  }
   130  
   131  @test "write to an idmap mount [userns]" {
   132  	setup_idmap_userns
   133  	setup_idmap_basic_mount
   134  
   135  	update_config '.process.args = ["sh", "-c", "touch /tmp/mount-1/bar && stat -c =%u=%g= /tmp/mount-1/bar"]'
   136  
   137  	runc run test_debian
   138  	[ "$status" -eq 0 ]
   139  	[[ "$output" == *"=0=0="* ]]
   140  }
   141  
   142  @test "write to an idmap mount [no userns]" {
   143  	setup_idmap_basic_mount
   144  
   145  	update_config '.process.args = ["sh", "-c", "touch /tmp/mount-1/bar && stat -c =%u=%g= /tmp/mount-1/bar"]'
   146  
   147  	runc run test_debian
   148  	# The write must fail because the user is unmapped.
   149  	[ "$status" -ne 0 ]
   150  	[[ "$output" == *"Value too large for defined data type"* ]] # ERANGE
   151  }
   152  
   153  @test "idmap mount with propagation flag [userns]" {
   154  	setup_idmap_userns
   155  	setup_idmap_basic_mount
   156  
   157  	update_config '.process.args = ["sh", "-c", "findmnt -o PROPAGATION /tmp/mount-1"]'
   158  	# Add the shared option to the idmap mount.
   159  	update_config '.mounts |= map((select(.source == "source-1/") | .options += ["shared"]) // .)'
   160  
   161  	runc run test_debian
   162  	[ "$status" -eq 0 ]
   163  	[[ "$output" == *"shared"* ]]
   164  }
   165  
   166  @test "idmap mount with relative path [userns]" {
   167  	setup_idmap_userns
   168  	setup_idmap_basic_mount
   169  
   170  	update_config '.process.args = ["sh", "-c", "stat -c =%u=%g= /tmp/mount-1/foo.txt"]'
   171  	# Switch the mount to have a relative mount destination.
   172  	update_config '.mounts |= map((select(.source == "source-1/") | .destination = "tmp/mount-1") // .)'
   173  
   174  	runc run test_debian
   175  	[ "$status" -eq 0 ]
   176  	[[ "$output" == *"=0=0="* ]]
   177  }
   178  
   179  @test "idmap mount with bind mount [userns]" {
   180  	setup_idmap_userns
   181  	setup_idmap_basic_mount
   182  	setup_bind_mount
   183  
   184  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/{,bind-}mount-1/foo.txt"]'
   185  
   186  	runc run test_debian
   187  	[ "$status" -eq 0 ]
   188  	[[ "$output" == *"=/tmp/mount-1/foo.txt:0=0="* ]]
   189  	[[ "$output" == *"=/tmp/bind-mount-1/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   190  }
   191  
   192  @test "idmap mount with bind mount [no userns]" {
   193  	setup_idmap_basic_mount
   194  	setup_bind_mount
   195  
   196  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/{,bind-}mount-1/foo.txt"]'
   197  
   198  	runc run test_debian
   199  	[ "$status" -eq 0 ]
   200  	[[ "$output" == *"=/tmp/mount-1/foo.txt:100000=100000="* ]]
   201  	[[ "$output" == *"=/tmp/bind-mount-1/foo.txt:0=0="* ]]
   202  }
   203  
   204  @test "two idmap mounts (same mapping) with two bind mounts [userns]" {
   205  	setup_idmap_userns
   206  
   207  	setup_idmap_basic_mount 1
   208  	setup_bind_mount 1
   209  	setup_bind_mount 2
   210  	setup_idmap_basic_mount 2
   211  
   212  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-[12]/foo.txt"]'
   213  
   214  	runc run test_debian
   215  	[ "$status" -eq 0 ]
   216  	[[ "$output" == *"=/tmp/mount-1/foo.txt:0=0="* ]]
   217  	[[ "$output" == *"=/tmp/mount-2/foo.txt:1=1="* ]]
   218  }
   219  
   220  @test "same idmap mount (different mappings) [userns]" {
   221  	setup_idmap_userns
   222  
   223  	# Mount the same directory with different mappings. Make sure we also use
   224  	# different mappings for uids and gids.
   225  	setup_idmap_single_mount 100:100000:100 200:100000:100 multi1
   226  	setup_idmap_single_mount 100:101000:100 200:102000:100 multi1 multi1-alt
   227  	setup_idmap_single_mount 100:102000:100 200:103000:100 multi1-symlink multi1-alt-sym
   228  
   229  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi1{,-alt{,-sym}}/{foo,bar,baz}.txt"]'
   230  
   231  	runc run test_debian
   232  	[ "$status" -eq 0 ]
   233  	[[ "$output" == *"=/tmp/mount-multi1/foo.txt:0=11="* ]]
   234  	[[ "$output" == *"=/tmp/mount-multi1/bar.txt:1=22="* ]]
   235  	[[ "$output" == *"=/tmp/mount-multi1/baz.txt:2=33="* ]]
   236  	[[ "$output" == *"=/tmp/mount-multi1-alt/foo.txt:1000=2011="* ]]
   237  	[[ "$output" == *"=/tmp/mount-multi1-alt/bar.txt:1001=2022="* ]]
   238  	[[ "$output" == *"=/tmp/mount-multi1-alt/baz.txt:1002=2033="* ]]
   239  	[[ "$output" == *"=/tmp/mount-multi1-alt-sym/foo.txt:2000=3011="* ]]
   240  	[[ "$output" == *"=/tmp/mount-multi1-alt-sym/bar.txt:2001=3022="* ]]
   241  	[[ "$output" == *"=/tmp/mount-multi1-alt-sym/baz.txt:2002=3033="* ]]
   242  }
   243  
   244  @test "same idmap mount (different mappings) [no userns]" {
   245  	# Mount the same directory with different mappings. Make sure we also use
   246  	# different mappings for uids and gids.
   247  	setup_idmap_single_mount 100:100000:100 200:100000:100 multi1
   248  	setup_idmap_single_mount 100:101000:100 200:102000:100 multi1 multi1-alt
   249  	setup_idmap_single_mount 100:102000:100 200:103000:100 multi1-symlink multi1-alt-sym
   250  
   251  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi1{,-alt{,-sym}}/{foo,bar,baz}.txt"]'
   252  
   253  	runc run test_debian
   254  	[ "$status" -eq 0 ]
   255  	[[ "$output" == *"=/tmp/mount-multi1/foo.txt:100000=100011="* ]]
   256  	[[ "$output" == *"=/tmp/mount-multi1/bar.txt:100001=100022="* ]]
   257  	[[ "$output" == *"=/tmp/mount-multi1/baz.txt:100002=100033="* ]]
   258  	[[ "$output" == *"=/tmp/mount-multi1-alt/foo.txt:101000=102011="* ]]
   259  	[[ "$output" == *"=/tmp/mount-multi1-alt/bar.txt:101001=102022="* ]]
   260  	[[ "$output" == *"=/tmp/mount-multi1-alt/baz.txt:101002=102033="* ]]
   261  	[[ "$output" == *"=/tmp/mount-multi1-alt-sym/foo.txt:102000=103011="* ]]
   262  	[[ "$output" == *"=/tmp/mount-multi1-alt-sym/bar.txt:102001=103022="* ]]
   263  	[[ "$output" == *"=/tmp/mount-multi1-alt-sym/baz.txt:102002=103033="* ]]
   264  }
   265  
   266  @test "multiple idmap mounts (different mappings) [userns]" {
   267  	setup_idmap_userns
   268  
   269  	# Make sure we use different mappings for uids and gids.
   270  	setup_idmap_single_mount 100:101100:3 200:101900:50 multi1
   271  	setup_idmap_single_mount 200:102200:3 200:102900:100 multi2
   272  	setup_idmap_single_mount 5000000:103000:1000 6000000:103000:500 multi3
   273  
   274  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi[123]/{foo,bar,baz}.txt"]'
   275  
   276  	runc run test_debian
   277  	[ "$status" -eq 0 ]
   278  	[[ "$output" == *"=/tmp/mount-multi1/foo.txt:1100=1911="* ]]
   279  	[[ "$output" == *"=/tmp/mount-multi1/bar.txt:1101=1922="* ]]
   280  	[[ "$output" == *"=/tmp/mount-multi1/baz.txt:1102=1933="* ]]
   281  	[[ "$output" == *"=/tmp/mount-multi2/foo.txt:2200=2911="* ]]
   282  	[[ "$output" == *"=/tmp/mount-multi2/bar.txt:2201=2922="* ]]
   283  	[[ "$output" == *"=/tmp/mount-multi2/baz.txt:2202=2933="* ]]
   284  	[[ "$output" == *"=/tmp/mount-multi3/foo.txt:3528=3491="* ]]
   285  	[[ "$output" == *"=/tmp/mount-multi3/bar.txt:3133=3337="* ]]
   286  	[[ "$output" == *"=/tmp/mount-multi3/baz.txt:3999=3444="* ]]
   287  }
   288  
   289  @test "multiple idmap mounts (different mappings) [no userns]" {
   290  	# Make sure we use different mappings for uids and gids.
   291  	setup_idmap_single_mount 100:1100:3 200:1900:50 multi1
   292  	setup_idmap_single_mount 200:2200:3 200:2900:100 multi2
   293  	setup_idmap_single_mount 5000000:3000:1000 6000000:3000:500 multi3
   294  
   295  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi[123]/{foo,bar,baz}.txt"]'
   296  
   297  	runc run test_debian
   298  	[ "$status" -eq 0 ]
   299  	[[ "$output" == *"=/tmp/mount-multi1/foo.txt:1100=1911="* ]]
   300  	[[ "$output" == *"=/tmp/mount-multi1/bar.txt:1101=1922="* ]]
   301  	[[ "$output" == *"=/tmp/mount-multi1/baz.txt:1102=1933="* ]]
   302  	[[ "$output" == *"=/tmp/mount-multi2/foo.txt:2200=2911="* ]]
   303  	[[ "$output" == *"=/tmp/mount-multi2/bar.txt:2201=2922="* ]]
   304  	[[ "$output" == *"=/tmp/mount-multi2/baz.txt:2202=2933="* ]]
   305  	[[ "$output" == *"=/tmp/mount-multi3/foo.txt:3528=3491="* ]]
   306  	[[ "$output" == *"=/tmp/mount-multi3/bar.txt:3133=3337="* ]]
   307  	[[ "$output" == *"=/tmp/mount-multi3/baz.txt:3999=3444="* ]]
   308  }
   309  
   310  @test "idmap mount (complicated mapping) [userns]" {
   311  	setup_idmap_userns
   312  
   313  	update_config '.mounts += [
   314  			{
   315  				"source": "source-multi1/",
   316  				"destination": "/tmp/mount-multi1",
   317  				"options": ["bind"],
   318  				"uidMappings": [
   319  					{"containerID": 100, "hostID": 101000, "size": 1},
   320  					{"containerID": 101, "hostID": 102000, "size": 1},
   321  					{"containerID": 102, "hostID": 103000, "size": 1}
   322  				],
   323  				"gidMappings": [
   324  					{"containerID": 210, "hostID": 101100, "size": 10},
   325  					{"containerID": 220, "hostID": 102200, "size": 10},
   326  					{"containerID": 230, "hostID": 103300, "size": 10}
   327  				]
   328  			}
   329  		]'
   330  
   331  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi1/{foo,bar,baz}.txt"]'
   332  	runc run test_debian
   333  	[ "$status" -eq 0 ]
   334  	[[ "$output" == *"=/tmp/mount-multi1/foo.txt:1000=1101="* ]]
   335  	[[ "$output" == *"=/tmp/mount-multi1/bar.txt:2000=2202="* ]]
   336  	[[ "$output" == *"=/tmp/mount-multi1/baz.txt:3000=3303="* ]]
   337  }
   338  
   339  @test "idmap mount (complicated mapping) [no userns]" {
   340  	update_config '.mounts += [
   341  			{
   342  				"source": "source-multi1/",
   343  				"destination": "/tmp/mount-multi1",
   344  				"options": ["bind"],
   345  				"uidMappings": [
   346  					{"containerID": 100, "hostID": 1000, "size": 1},
   347  					{"containerID": 101, "hostID": 2000, "size": 1},
   348  					{"containerID": 102, "hostID": 3000, "size": 1}
   349  				],
   350  				"gidMappings": [
   351  					{"containerID": 210, "hostID": 1100, "size": 10},
   352  					{"containerID": 220, "hostID": 2200, "size": 10},
   353  					{"containerID": 230, "hostID": 3300, "size": 10}
   354  				]
   355  			}
   356  		]'
   357  
   358  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-multi1/{foo,bar,baz}.txt"]'
   359  	runc run test_debian
   360  	[ "$status" -eq 0 ]
   361  	[[ "$output" == *"=/tmp/mount-multi1/foo.txt:1000=1101="* ]]
   362  	[[ "$output" == *"=/tmp/mount-multi1/bar.txt:2000=2202="* ]]
   363  	[[ "$output" == *"=/tmp/mount-multi1/baz.txt:3000=3303="* ]]
   364  }
   365  
   366  @test "idmap mount (non-recursive idmap) [userns]" {
   367  	setup_idmap_userns
   368  
   369  	setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1"
   370  	setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2"
   371  
   372  	update_config '.mounts += [
   373  			{
   374  				"source": "mnt-subtree/",
   375  				"destination": "/tmp/mount-tree",
   376  				"options": ["rbind"],
   377  				"uidMappings": [
   378  					{"containerID": 100, "hostID": 101000, "size": 3},
   379  					{"containerID": 200, "hostID": 102000, "size": 3},
   380  					{"containerID": 300, "hostID": 103000, "size": 3}
   381  				],
   382  				"gidMappings": [
   383  					{"containerID": 210, "hostID": 101100, "size": 10},
   384  					{"containerID": 220, "hostID": 102200, "size": 10},
   385  					{"containerID": 230, "hostID": 103300, "size": 10}
   386  				]
   387  			}
   388  		]'
   389  
   390  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]'
   391  	runc run test_debian
   392  	[ "$status" -eq 0 ]
   393  	[[ "$output" == *"=/tmp/mount-tree/foo.txt:1000=1101="* ]]
   394  	[[ "$output" == *"=/tmp/mount-tree/bar.txt:2000=2202="* ]]
   395  	[[ "$output" == *"=/tmp/mount-tree/baz.txt:3000=3303="* ]]
   396  	# Because we used "idmap", the child mounts were not remapped recursively.
   397  	[[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   398  	[[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   399  	[[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   400  	[[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   401  	[[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   402  	[[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   403  }
   404  
   405  @test "idmap mount (non-recursive idmap) [no userns]" {
   406  	setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1"
   407  	setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2"
   408  
   409  	update_config '.mounts += [
   410  			{
   411  				"source": "mnt-subtree/",
   412  				"destination": "/tmp/mount-tree",
   413  				"options": ["rbind"],
   414  				"uidMappings": [
   415  					{"containerID": 100, "hostID": 101000, "size": 3},
   416  					{"containerID": 200, "hostID": 102000, "size": 3},
   417  					{"containerID": 300, "hostID": 103000, "size": 3}
   418  				],
   419  				"gidMappings": [
   420  					{"containerID": 210, "hostID": 101100, "size": 10},
   421  					{"containerID": 220, "hostID": 102200, "size": 10},
   422  					{"containerID": 230, "hostID": 103300, "size": 10}
   423  				]
   424  			}
   425  		]'
   426  
   427  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]'
   428  	runc run test_debian
   429  	[ "$status" -eq 0 ]
   430  	[[ "$output" == *"=/tmp/mount-tree/foo.txt:101000=101101="* ]]
   431  	[[ "$output" == *"=/tmp/mount-tree/bar.txt:102000=102202="* ]]
   432  	[[ "$output" == *"=/tmp/mount-tree/baz.txt:103000=103303="* ]]
   433  	# Because we used "idmap", the child mounts were not remapped recursively.
   434  	[[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:100=211="* ]]
   435  	[[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:101=222="* ]]
   436  	[[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:102=233="* ]]
   437  	[[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:200=211="* ]]
   438  	[[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:201=222="* ]]
   439  	[[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:202=233="* ]]
   440  }
   441  
   442  @test "idmap mount (idmap flag) [userns]" {
   443  	setup_idmap_userns
   444  
   445  	setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1"
   446  	setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2"
   447  
   448  	update_config '.mounts += [
   449  			{
   450  				"source": "mnt-subtree/",
   451  				"destination": "/tmp/mount-tree",
   452  				"options": ["rbind", "idmap"],
   453  				"uidMappings": [
   454  					{"containerID": 100, "hostID": 101000, "size": 3},
   455  					{"containerID": 200, "hostID": 102000, "size": 3},
   456  					{"containerID": 300, "hostID": 103000, "size": 3}
   457  				],
   458  				"gidMappings": [
   459  					{"containerID": 210, "hostID": 101100, "size": 10},
   460  					{"containerID": 220, "hostID": 102200, "size": 10},
   461  					{"containerID": 230, "hostID": 103300, "size": 10}
   462  				]
   463  			}
   464  		]'
   465  
   466  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]'
   467  	runc run test_debian
   468  	[ "$status" -eq 0 ]
   469  	[[ "$output" == *"=/tmp/mount-tree/foo.txt:1000=1101="* ]]
   470  	[[ "$output" == *"=/tmp/mount-tree/bar.txt:2000=2202="* ]]
   471  	[[ "$output" == *"=/tmp/mount-tree/baz.txt:3000=3303="* ]]
   472  	# Because we used "idmap", the child mounts were not remapped recursively.
   473  	[[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   474  	[[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   475  	[[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   476  	[[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   477  	[[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   478  	[[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   479  }
   480  
   481  @test "idmap mount (idmap flag) [no userns]" {
   482  	setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1"
   483  	setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2"
   484  
   485  	update_config '.mounts += [
   486  			{
   487  				"source": "mnt-subtree/",
   488  				"destination": "/tmp/mount-tree",
   489  				"options": ["rbind", "idmap"],
   490  				"uidMappings": [
   491  					{"containerID": 100, "hostID": 101000, "size": 3},
   492  					{"containerID": 200, "hostID": 102000, "size": 3},
   493  					{"containerID": 300, "hostID": 103000, "size": 3}
   494  				],
   495  				"gidMappings": [
   496  					{"containerID": 210, "hostID": 101100, "size": 10},
   497  					{"containerID": 220, "hostID": 102200, "size": 10},
   498  					{"containerID": 230, "hostID": 103300, "size": 10}
   499  				]
   500  			}
   501  		]'
   502  
   503  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]'
   504  	runc run test_debian
   505  	[ "$status" -eq 0 ]
   506  	[[ "$output" == *"=/tmp/mount-tree/foo.txt:101000=101101="* ]]
   507  	[[ "$output" == *"=/tmp/mount-tree/bar.txt:102000=102202="* ]]
   508  	[[ "$output" == *"=/tmp/mount-tree/baz.txt:103000=103303="* ]]
   509  	# Because we used "idmap", the child mounts were not remapped recursively.
   510  	[[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:100=211="* ]]
   511  	[[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:101=222="* ]]
   512  	[[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:102=233="* ]]
   513  	[[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:200=211="* ]]
   514  	[[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:201=222="* ]]
   515  	[[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:202=233="* ]]
   516  }
   517  
   518  @test "idmap mount (ridmap flag) [userns]" {
   519  	setup_idmap_userns
   520  
   521  	setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1"
   522  	setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2"
   523  
   524  	update_config '.mounts += [
   525  			{
   526  				"source": "mnt-subtree/",
   527  				"destination": "/tmp/mount-tree",
   528  				"options": ["rbind", "ridmap"],
   529  				"uidMappings": [
   530  					{"containerID": 100, "hostID": 101000, "size": 3},
   531  					{"containerID": 200, "hostID": 102000, "size": 3},
   532  					{"containerID": 300, "hostID": 103000, "size": 3}
   533  				],
   534  				"gidMappings": [
   535  					{"containerID": 210, "hostID": 101100, "size": 10},
   536  					{"containerID": 220, "hostID": 102200, "size": 10},
   537  					{"containerID": 230, "hostID": 103300, "size": 10}
   538  				]
   539  			}
   540  		]'
   541  
   542  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]'
   543  	runc run test_debian
   544  	[ "$status" -eq 0 ]
   545  	[[ "$output" == *"=/tmp/mount-tree/foo.txt:1000=1101="* ]]
   546  	[[ "$output" == *"=/tmp/mount-tree/bar.txt:2000=2202="* ]]
   547  	[[ "$output" == *"=/tmp/mount-tree/baz.txt:3000=3303="* ]]
   548  	# The child mounts have the same mapping applied.
   549  	[[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:1000=1101="* ]]
   550  	[[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:1001=2202="* ]]
   551  	[[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:1002=3303="* ]]
   552  	[[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:2000=1101="* ]]
   553  	[[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:2001=2202="* ]]
   554  	[[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:2002=3303="* ]]
   555  }
   556  
   557  @test "idmap mount (ridmap flag) [no userns]" {
   558  	setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1"
   559  	setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2"
   560  
   561  	update_config '.mounts += [
   562  			{
   563  				"source": "mnt-subtree/",
   564  				"destination": "/tmp/mount-tree",
   565  				"options": ["rbind", "ridmap"],
   566  				"uidMappings": [
   567  					{"containerID": 100, "hostID": 101000, "size": 3},
   568  					{"containerID": 200, "hostID": 102000, "size": 3},
   569  					{"containerID": 300, "hostID": 103000, "size": 3}
   570  				],
   571  				"gidMappings": [
   572  					{"containerID": 210, "hostID": 101100, "size": 10},
   573  					{"containerID": 220, "hostID": 102200, "size": 10},
   574  					{"containerID": 230, "hostID": 103300, "size": 10}
   575  				]
   576  			}
   577  		]'
   578  
   579  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]'
   580  	runc run test_debian
   581  	[ "$status" -eq 0 ]
   582  	[[ "$output" == *"=/tmp/mount-tree/foo.txt:101000=101101="* ]]
   583  	[[ "$output" == *"=/tmp/mount-tree/bar.txt:102000=102202="* ]]
   584  	[[ "$output" == *"=/tmp/mount-tree/baz.txt:103000=103303="* ]]
   585  	# The child mounts have the same mapping applied.
   586  	[[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:101000=101101="* ]]
   587  	[[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:101001=102202="* ]]
   588  	[[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:101002=103303="* ]]
   589  	[[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:102000=101101="* ]]
   590  	[[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:102001=102202="* ]]
   591  	[[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:102002=103303="* ]]
   592  }
   593  
   594  @test "idmap mount (idmap flag, implied mapping) [userns]" {
   595  	setup_idmap_userns
   596  
   597  	setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1"
   598  	setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2"
   599  
   600  	update_config '.mounts += [
   601  			{
   602  				"source": "mnt-subtree/",
   603  				"destination": "/tmp/mount-tree",
   604  				"options": ["rbind", "idmap"],
   605  			}
   606  		]'
   607  
   608  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]'
   609  	runc run test_debian
   610  	[ "$status" -eq 0 ]
   611  	[[ "$output" == *"=/tmp/mount-tree/foo.txt:100=211="* ]]
   612  	[[ "$output" == *"=/tmp/mount-tree/bar.txt:200=222="* ]]
   613  	[[ "$output" == *"=/tmp/mount-tree/baz.txt:300=233="* ]]
   614  	# Because we used "idmap", the child mounts were not remapped recursively.
   615  	[[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   616  	[[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   617  	[[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   618  	[[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   619  	[[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   620  	[[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   621  }
   622  
   623  @test "idmap mount (ridmap flag, implied mapping) [userns]" {
   624  	setup_idmap_userns
   625  
   626  	setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1"
   627  	setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2"
   628  
   629  	update_config '.mounts += [
   630  			{
   631  				"source": "mnt-subtree/",
   632  				"destination": "/tmp/mount-tree",
   633  				"options": ["rbind", "ridmap"],
   634  			}
   635  		]'
   636  
   637  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]'
   638  	runc run test_debian
   639  	[ "$status" -eq 0 ]
   640  	[[ "$output" == *"=/tmp/mount-tree/foo.txt:100=211="* ]]
   641  	[[ "$output" == *"=/tmp/mount-tree/bar.txt:200=222="* ]]
   642  	[[ "$output" == *"=/tmp/mount-tree/baz.txt:300=233="* ]]
   643  	# The child mounts have the same mapping applied.
   644  	[[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:100=211="* ]]
   645  	[[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:101=222="* ]]
   646  	[[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:102=233="* ]]
   647  	[[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:200=211="* ]]
   648  	[[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:201=222="* ]]
   649  	[[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:202=233="* ]]
   650  }
   651  
   652  @test "idmap mount (idmap flag, implied mapping, userns join) [userns]" {
   653  	# Create a detached container with the id-mapping we want.
   654  	cp config.json config.json.bak
   655  	update_config '.linux.namespaces += [{"type": "user"}]
   656  		| .linux.uidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}]
   657  		| .linux.gidMappings += [{"containerID": 0, "hostID": 100000, "size": 65536}]'
   658  	update_config '.process.args = ["sleep", "infinity"]'
   659  
   660  	runc run -d --console-socket "$CONSOLE_SOCKET" target_userns
   661  	[ "$status" -eq 0 ]
   662  
   663  	# Configure our container to attach to the first container's userns.
   664  	target_pid="$(__runc state target_userns | jq .pid)"
   665  	update_config '.linux.namespaces |= map(if .type == "user" then (.path = "/proc/'"$target_pid"'/ns/" + .type) else . end)'
   666  	update_config 'del(.linux.uidMappings) | del(.linux.gidMappings)'
   667  
   668  	setup_host_bind_mount "source-multi1/" "mnt-subtree/multi1"
   669  	setup_host_bind_mount "source-multi2/" "mnt-subtree/multi2"
   670  
   671  	update_config '.mounts += [
   672  			{
   673  				"source": "mnt-subtree/",
   674  				"destination": "/tmp/mount-tree",
   675  				"options": ["rbind", "idmap"],
   676  			}
   677  		]'
   678  
   679  	update_config '.process.args = ["bash", "-c", "stat -c =%n:%u=%g= /tmp/mount-tree{,/multi1,/multi2}/{foo,bar,baz}.txt"]'
   680  	runc run test_debian
   681  	[ "$status" -eq 0 ]
   682  	[[ "$output" == *"=/tmp/mount-tree/foo.txt:100=211="* ]]
   683  	[[ "$output" == *"=/tmp/mount-tree/bar.txt:200=222="* ]]
   684  	[[ "$output" == *"=/tmp/mount-tree/baz.txt:300=233="* ]]
   685  	# Because we used "idmap", the child mounts were not remapped recursively.
   686  	[[ "$output" == *"=/tmp/mount-tree/multi1/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   687  	[[ "$output" == *"=/tmp/mount-tree/multi1/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   688  	[[ "$output" == *"=/tmp/mount-tree/multi1/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   689  	[[ "$output" == *"=/tmp/mount-tree/multi2/foo.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   690  	[[ "$output" == *"=/tmp/mount-tree/multi2/bar.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   691  	[[ "$output" == *"=/tmp/mount-tree/multi2/baz.txt:$OVERFLOW_UID=$OVERFLOW_GID="* ]]
   692  }