From eb5bd4fa6adfe9f2e41a5a5a2463857ae5f7a0c6 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Thu, 7 Sep 2017 09:54:46 +1000 Subject: [PATCH] tests: add tests for rootless multi-mapping configurations Enable several previously disabled tests (for the idmap execution mode) for rootless containers, in addition to making all tests use the additional mappings. At the moment there's no strong need to add any additional tests purely for rootless_idmap. Signed-off-by: Aleksa Sarai --- Dockerfile | 1 + tests/integration/exec.bats | 6 ++-- tests/integration/helpers.bash | 43 +++++++++++++++++++++++---- tests/integration/spec.bats | 2 +- tests/integration/start_detached.bats | 4 +-- tests/integration/start_hello.bats | 4 +-- tests/integration/tty.bats | 16 +++++----- tests/rootless.sh | 35 +++++++++++++++++++++- 8 files changed, 88 insertions(+), 23 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9d6b96fbc..1b36d0d91 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,7 @@ RUN apt-get update && apt-get install -y \ protobuf-c-compiler \ protobuf-compiler \ python-minimal \ + uidmap \ --no-install-recommends \ && apt-get clean diff --git a/tests/integration/exec.bats b/tests/integration/exec.bats index 70730de88..8d943aab7 100644 --- a/tests/integration/exec.bats +++ b/tests/integration/exec.bats @@ -100,8 +100,8 @@ function teardown() { } @test "runc exec --user" { - # --user can't work in rootless containers - requires root + # --user can't work in rootless containers that don't have idmap. + [[ "$ROOTLESS" -ne 0 ]] && requires rootless_idmap # run busybox detached runc run -d --console-socket $CONSOLE_SOCKET test_busybox @@ -110,5 +110,5 @@ function teardown() { runc exec --user 1000:1000 test_busybox id [ "$status" -eq 0 ] - [[ ${output} == "uid=1000 gid=1000" ]] + [[ "${output}" == "uid=1000 gid=1000"* ]] } diff --git a/tests/integration/helpers.bash b/tests/integration/helpers.bash index 29e0fef68..e44fcaa7e 100644 --- a/tests/integration/helpers.bash +++ b/tests/integration/helpers.bash @@ -58,15 +58,41 @@ function __runc() { "$RUNC" --log /proc/self/fd/2 --root "$ROOT" "$@" } -# Wrapper for runc spec. +# Wrapper for runc spec, which takes only one argument (the bundle path). function runc_spec() { - local args="" + ! [[ "$#" > 1 ]] + + local args=() + local bundle="" if [ "$ROOTLESS" -ne 0 ]; then - args+="--rootless" + args+=("--rootless") + fi + if [ "$#" -ne 0 ]; then + bundle="$1" + args+=("--bundle" "$bundle") fi - runc spec $args "$@" + runc spec "${args[@]}" + + # Always add additional mappings if we have idmaps. + if [[ "$ROOTLESS" -ne 0 ]] && [[ "$ROOTLESS_FEATURES" == *"idmap"* ]]; then + runc_rootless_idmap "$bundle" + fi +} + +# Shortcut to add additional uids and gids, based on the values set as part of +# a rootless configuration. +function runc_rootless_idmap() { + bundle="${1:-.}" + cat "$bundle/config.json" \ + | jq '.mounts |= map((select(.type == "devpts") | .options += ["gid=5"]) // .)' \ + | jq '.linux.uidMappings |= .+ [{"hostID": '"$ROOTLESS_UIDMAP_START"', "containerID": 1000, "size": '"$ROOTLESS_UIDMAP_LENGTH"'}]' \ + | jq '.linux.gidMappings |= .+ [{"hostID": '"$ROOTLESS_GIDMAP_START"', "containerID": 100, "size": 1}]' \ + | jq '.linux.gidMappings |= .+ [{"hostID": '"$(($ROOTLESS_GIDMAP_START+10))"', "containerID": 1, "size": 20}]' \ + | jq '.linux.gidMappings |= .+ [{"hostID": '"$(($ROOTLESS_GIDMAP_START+100))"', "containerID": 1000, "size": '"$(($ROOTLESS_GIDMAP_LENGTH-1000))"'}]' \ + >"$bundle/config.json.tmp" + mv "$bundle/config.json"{.tmp,} } # Fails the current test, providing the error given. @@ -90,14 +116,19 @@ function requires() { skip "test requires ${var}" fi ;; + rootless_idmap) + if [[ "$ROOTLESS_FEATURES" != *"idmap"* ]]; then + skip "test requires ${var}" + fi + ;; cgroups_kmem) if [ ! -e "$KMEM" ]; then - skip "Test requires ${var}." + skip "Test requires ${var}" fi ;; cgroups_rt) if [ ! -e "$RT_PERIOD" ]; then - skip "Test requires ${var}." + skip "Test requires ${var}" fi ;; *) diff --git a/tests/integration/spec.bats b/tests/integration/spec.bats index 606170606..c9ba2aaac 100644 --- a/tests/integration/spec.bats +++ b/tests/integration/spec.bats @@ -51,7 +51,7 @@ function teardown() { [ ! -e "$HELLO_BUNDLE"/config.json ] # test generation of spec does not return an error - runc_spec --bundle "$HELLO_BUNDLE" + runc_spec "$HELLO_BUNDLE" [ "$status" -eq 0 ] # test generation of spec created our config.json (spec) diff --git a/tests/integration/start_detached.bats b/tests/integration/start_detached.bats index 0dc5e0d87..7f177b865 100644 --- a/tests/integration/start_detached.bats +++ b/tests/integration/start_detached.bats @@ -21,8 +21,8 @@ function teardown() { } @test "runc run detached ({u,g}id != 0)" { - # cannot start containers as another user in rootless setup - requires root + # cannot start containers as another user in rootless setup without idmap + [[ "$ROOTLESS" -ne 0 ]] && requires rootless_idmap # replace "uid": 0 with "uid": 1000 # and do a similar thing for gid. diff --git a/tests/integration/start_hello.bats b/tests/integration/start_hello.bats index 2e9357280..a706be27d 100644 --- a/tests/integration/start_hello.bats +++ b/tests/integration/start_hello.bats @@ -21,8 +21,8 @@ function teardown() { } @test "runc run ({u,g}id != 0)" { - # cannot start containers as another user in rootless setup - requires root + # cannot start containers as another user in rootless setup without idmap + [[ "$ROOTLESS" -ne 0 ]] && requires rootless_idmap # replace "uid": 0 with "uid": 1000 # and do a similar thing for gid. diff --git a/tests/integration/tty.bats b/tests/integration/tty.bats index 985a9b757..a59652bba 100644 --- a/tests/integration/tty.bats +++ b/tests/integration/tty.bats @@ -24,9 +24,9 @@ function teardown() { } @test "runc run [tty owner]" { - # tty chmod is not doable in rootless containers. + # tty chmod is not doable in rootless containers without idmap. # TODO: this can be made as a change to the gid test. - requires root + [[ "$ROOTLESS" -ne 0 ]] && requires rootless_idmap # Replace sh script with stat. sed -i 's/"sh"/"sh", "-c", "stat -c %u:%g $(tty) | tr : \\\\\\\\n"/' config.json @@ -40,8 +40,8 @@ function teardown() { } @test "runc run [tty owner] ({u,g}id != 0)" { - # tty chmod is not doable in rootless containers. - requires root + # tty chmod is not doable in rootless containers without idmap. + [[ "$ROOTLESS" -ne 0 ]] && requires rootless_idmap # replace "uid": 0 with "uid": 1000 # and do a similar thing for gid. @@ -76,9 +76,9 @@ function teardown() { } @test "runc exec [tty owner]" { - # tty chmod is not doable in rootless containers. + # tty chmod is not doable in rootless containers without idmap. # TODO: this can be made as a change to the gid test. - requires root + [[ "$ROOTLESS" -ne 0 ]] && requires rootless_idmap # run busybox detached runc run -d --console-socket $CONSOLE_SOCKET test_busybox @@ -95,8 +95,8 @@ function teardown() { } @test "runc exec [tty owner] ({u,g}id != 0)" { - # tty chmod is not doable in rootless containers. - requires root + # tty chmod is not doable in rootless containers without idmap. + [[ "$ROOTLESS" -ne 0 ]] && requires rootless_idmap # replace "uid": 0 with "uid": 1000 # and do a similar thing for gid. diff --git a/tests/rootless.sh b/tests/rootless.sh index 2613c7022..cb2c06479 100755 --- a/tests/rootless.sh +++ b/tests/rootless.sh @@ -19,9 +19,42 @@ # a new feature, please match the existing style. Add an entry to $ALL_FEATURES, # and add an enable_* and disable_* hook. -ALL_FEATURES=() +ALL_FEATURES=("idmap") ROOT="$(readlink -f "$(dirname "${BASH_SOURCE}")/..")" +# FEATURE: Opportunistic new{uid,gid}map support, allowing a rootless container +# to be set up with the usage of helper setuid binaries. + +function enable_idmap() { + export ROOTLESS_UIDMAP_START=100000 ROOTLESS_UIDMAP_LENGTH=65536 + export ROOTLESS_GIDMAP_START=200000 ROOTLESS_GIDMAP_LENGTH=65536 + + # Set up sub{uid,gid} mappings. + [ -e /etc/subuid.tmp ] && mv /etc/subuid{.tmp,} + ( grep -v '^rootless' /etc/subuid ; echo "rootless:$ROOTLESS_UIDMAP_START:$ROOTLESS_UIDMAP_LENGTH" ) > /etc/subuid.tmp + mv /etc/subuid{.tmp,} + [ -e /etc/subgid.tmp ] && mv /etc/subgid{.tmp,} + ( grep -v '^rootless' /etc/subgid ; echo "rootless:$ROOTLESS_GIDMAP_START:$ROOTLESS_GIDMAP_LENGTH" ) > /etc/subgid.tmp + mv /etc/subgid{.tmp,} + + # Reactivate new{uid,gid}map helpers if applicable. + [ -e /usr/bin/unused-newuidmap ] && mv /usr/bin/{unused-,}newuidmap + [ -e /usr/bin/unused-newgidmap ] && mv /usr/bin/{unused-,}newgidmap +} + +function disable_idmap() { + export ROOTLESS_UIDMAP_START ROOTLESS_UIDMAP_LENGTH + export ROOTLESS_GIDMAP_START ROOTLESS_GIDMAP_LENGTH + + # Deactivate sub{uid,gid} mappings. + [ -e /etc/subuid ] && mv /etc/subuid{,.tmp} + [ -e /etc/subgid ] && mv /etc/subgid{,.tmp} + + # Deactivate new{uid,gid}map helpers. setuid is preserved with mv(1). + [ -e /usr/bin/newuidmap ] && mv /usr/bin/{,unused-}newuidmap + [ -e /usr/bin/newgidmap ] && mv /usr/bin/{,unused-}newgidmap +} + # Create a powerset of $ALL_FEATURES (the set of all subsets of $ALL_FEATURES). # We test all of the possible combinations (as long as we don't add too many # feature knobs this shouldn't take too long -- but the number of tested