Files
runc/tests/integration/idmap.bats
Aleksa Sarai 3b57e45cbf mount: add support for ridmap and idmap
ridmap indicates that the id mapping should be applied recursively (only
really relevant for rbind mount entries), and idmap indicates that it
should not be applied recursively (the default). If no mappings are
specified for the mount, we use the userns configuration of the
container. This matches the behaviour in the currently-unreleased
runtime-spec.

This includes a minor change to the state.json serialisation format, but
because there has been no released version of runc with commit
fbf183c6f8 ("Add uid and gid mappings to mounts"), we can safely make
this change without affecting running containers. Doing it this way
makes it much easier to handle m.IsIDMapped() and indicating that a
mapping has been specified.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2023-12-14 11:36:42 +11:00

693 lines
26 KiB
Bash

#!/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}"
setup_idmap_single_mount 0:100000:65536 0:100000:65536 "$mountname"
}
@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="* ]]
}