github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/tests/rootless.sh (about) 1 #!/bin/bash 2 # Copyright (C) 2017 SUSE LLC 3 # 4 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # you may not use this file except in compliance with the License. 6 # You may obtain a copy of the License at 7 # 8 # http://www.apache.org/licenses/LICENSE-2.0 9 # 10 # Unless required by applicable law or agreed to in writing, software 11 # distributed under the License is distributed on an "AS IS" BASIS, 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 # See the License for the specific language governing permissions and 14 # limitations under the License. 15 16 # rootless.sh -- Runner for rootless container tests. The purpose of this 17 # script is to allow for the addition (and testing) of "opportunistic" features 18 # to rootless containers while still testing the base features. In order to add 19 # a new feature, please match the existing style. Add an entry to $ALL_FEATURES, 20 # and add an enable_* and disable_* hook. 21 22 set -e -u -o pipefail 23 : "${ROOTLESS_TESTPATH:=}" 24 25 ALL_FEATURES=("idmap" "cgroup") 26 # cgroup is managed by systemd when RUNC_USE_SYSTEMD is set. 27 if [ -v RUNC_USE_SYSTEMD ]; then 28 ALL_FEATURES=("idmap") 29 fi 30 ROOT="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")" 31 32 # FEATURE: Opportunistic new{uid,gid}map support, allowing a rootless container 33 # to be set up with the usage of helper setuid binaries. 34 35 function enable_idmap() { 36 export ROOTLESS_UIDMAP_START=100000 ROOTLESS_UIDMAP_LENGTH=65536 37 export ROOTLESS_GIDMAP_START=200000 ROOTLESS_GIDMAP_LENGTH=65536 38 39 # Set up sub{uid,gid} mappings. 40 [ -e /etc/subuid.tmp ] && mv /etc/subuid{.tmp,} 41 ( 42 grep -v '^rootless' /etc/subuid 43 echo "rootless:$ROOTLESS_UIDMAP_START:$ROOTLESS_UIDMAP_LENGTH" 44 ) >/etc/subuid.tmp 45 mv /etc/subuid{.tmp,} 46 [ -e /etc/subgid.tmp ] && mv /etc/subgid{.tmp,} 47 ( 48 grep -v '^rootless' /etc/subgid 49 echo "rootless:$ROOTLESS_GIDMAP_START:$ROOTLESS_GIDMAP_LENGTH" 50 ) >/etc/subgid.tmp 51 mv /etc/subgid{.tmp,} 52 53 # Reactivate new{uid,gid}map helpers if applicable. 54 [ -e /usr/bin/unused-newuidmap ] && mv /usr/bin/{unused-,}newuidmap 55 [ -e /usr/bin/unused-newgidmap ] && mv /usr/bin/{unused-,}newgidmap 56 57 # Create a directory owned by $AUX_UID inside container, to be used 58 # by a test case in cwd.bats. This setup can't be done by the test itself, 59 # as it needs root for chown. 60 export AUX_UID=1024 61 AUX_DIR="$(mktemp -d)" 62 # 1000 is linux.uidMappings.containerID value, 63 # as set by runc_rootless_idmap 64 chown "$((ROOTLESS_UIDMAP_START - 1000 + AUX_UID))" "$AUX_DIR" 65 export AUX_DIR 66 } 67 68 function disable_idmap() { 69 export ROOTLESS_UIDMAP_START ROOTLESS_UIDMAP_LENGTH 70 export ROOTLESS_GIDMAP_START ROOTLESS_GIDMAP_LENGTH 71 72 # Deactivate sub{uid,gid} mappings. 73 [ -e /etc/subuid ] && mv /etc/subuid{,.tmp} 74 [ -e /etc/subgid ] && mv /etc/subgid{,.tmp} 75 76 # Deactivate new{uid,gid}map helpers. setuid is preserved with mv(1). 77 [ -e /usr/bin/newuidmap ] && mv /usr/bin/{,unused-}newuidmap 78 [ -e /usr/bin/newgidmap ] && mv /usr/bin/{,unused-}newgidmap 79 80 return 0 81 } 82 83 function cleanup() { 84 if [ -v AUX_DIR ]; then 85 rmdir "$AUX_DIR" 86 unset AUX_DIX 87 fi 88 } 89 90 # FEATURE: Opportunistic cgroups support, allowing a rootless container to set 91 # resource limits on condition that cgroupsPath is set to a path the 92 # rootless user has permissions on. 93 94 # List of cgroups. We handle name= cgroups as well as combined 95 # (comma-separated) cgroups and correctly split and/or strip them. 96 # shellcheck disable=SC2207 97 ALL_CGROUPS=($(cut -d: -f2 </proc/self/cgroup | sed -E '{s/^name=//;s/,/\n/;/^$/D}')) 98 CGROUP_MOUNT="/sys/fs/cgroup" 99 CGROUP_PATH="/runc-cgroups-integration-test" 100 101 function enable_cgroup() { 102 # Set up cgroups for use in rootless containers. 103 for cg in "${ALL_CGROUPS[@]}"; do 104 mkdir -p "$CGROUP_MOUNT/$cg$CGROUP_PATH" 105 # We only need to allow write access to {cgroup.procs,tasks} and the 106 # directory. Rather than changing the owner entirely, we just change 107 # the group and then allow write access to the group (in order to 108 # further limit the possible DAC permissions that runc could use). 109 chown root:rootless "$CGROUP_MOUNT/$cg$CGROUP_PATH/"{,cgroup.procs,tasks} 110 chmod g+rwx "$CGROUP_MOUNT/$cg$CGROUP_PATH/"{,cgroup.procs,tasks} 111 # Due to cpuset's semantics we need to give extra permissions to allow 112 # for runc to set up the hierarchy. XXX: This really shouldn't be 113 # necessary, and might actually be a bug in our impl of cgroup 114 # handling. 115 [ "$cg" = "cpuset" ] && chown rootless:rootless "$CGROUP_MOUNT/$cg$CGROUP_PATH/cpuset."{cpus,mems} 116 # The following is required by "update rt period and runtime". 117 if [ "$cg" = "cpu" ]; then 118 if [[ -e "$CGROUP_MOUNT/$cg$CGROUP_PATH/cpu.rt_period_us" ]]; then 119 chown rootless:rootless "$CGROUP_MOUNT/$cg$CGROUP_PATH/cpu.rt_period_us" 120 fi 121 if [[ -e "$CGROUP_MOUNT/$cg$CGROUP_PATH/cpu.rt_runtime_us" ]]; then 122 chown rootless:rootless "$CGROUP_MOUNT/$cg$CGROUP_PATH/cpu.rt_runtime_us" 123 fi 124 fi 125 done 126 # cgroup v2 127 if [[ -e "$CGROUP_MOUNT/cgroup.controllers" ]]; then 128 # Enable controllers. Some controller (e.g. memory) may fail on containerized environment. 129 set -x 130 # shellcheck disable=SC2013 131 for f in $(cat "$CGROUP_MOUNT/cgroup.controllers"); do echo "+$f" >"$CGROUP_MOUNT/cgroup.subtree_control"; done 132 set +x 133 # Create the cgroup. 134 mkdir -p "$CGROUP_MOUNT/$CGROUP_PATH" 135 # chown/chmod dir + cgroup.subtree_control + cgroup.procs + parent's cgroup.procs. 136 # See https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#delegation-containment 137 chown root:rootless "$CGROUP_MOUNT/$CGROUP_PATH" "$CGROUP_MOUNT/$CGROUP_PATH/cgroup.subtree_control" "$CGROUP_MOUNT/$CGROUP_PATH/cgroup.procs" "$CGROUP_MOUNT/cgroup.procs" 138 chmod g+rwx "$CGROUP_MOUNT/$CGROUP_PATH" 139 chmod g+rw "$CGROUP_MOUNT/$CGROUP_PATH/cgroup.subtree_control" "$CGROUP_MOUNT/$CGROUP_PATH/cgroup.procs" "$CGROUP_MOUNT/cgroup.procs" 140 fi 141 } 142 143 function disable_cgroup() { 144 # Remove cgroups used in rootless containers. 145 for cg in "${ALL_CGROUPS[@]}"; do 146 [ -d "$CGROUP_MOUNT/$cg$CGROUP_PATH" ] && rmdir "$CGROUP_MOUNT/$cg$CGROUP_PATH" 147 done 148 # cgroup v2 149 [ -d "$CGROUP_MOUNT/$CGROUP_PATH" ] && rmdir "$CGROUP_MOUNT/$CGROUP_PATH" 150 151 return 0 152 } 153 154 # Create a powerset of $ALL_FEATURES (the set of all subsets of $ALL_FEATURES). 155 # We test all of the possible combinations (as long as we don't add too many 156 # feature knobs this shouldn't take too long -- but the number of tested 157 # combinations is O(2^n)). 158 function powerset() { 159 eval printf '%s' "$(printf '{,%s+}' "$@")": 160 } 161 features_powerset="$(powerset "${ALL_FEATURES[@]}")" 162 163 # Make sure we have container images downloaded, as otherwise 164 # rootless user won't be able to write to $TESTDATA. 165 "$ROOT"/tests/integration/get-images.sh >/dev/null 166 167 # Iterate over the powerset of all features. 168 IFS=: 169 idx=0 170 for enabled_features in $features_powerset; do 171 ((++idx)) 172 printf "[%.2d] run rootless tests ... (${enabled_features%%+})\n" "$idx" 173 174 unset IFS 175 for feature in "${ALL_FEATURES[@]}"; do 176 hook_func="disable_$feature" 177 grep -E "(^|\+)$feature(\+|$)" <<<"$enabled_features" &>/dev/null && hook_func="enable_$feature" 178 "$hook_func" 179 done 180 181 # Run the test suite! 182 echo "path: $PATH" 183 export ROOTLESS_FEATURES="$enabled_features" 184 if [ -v RUNC_USE_SYSTEMD ]; then 185 # We use `ssh rootless@localhost` instead of `sudo -u rootless` for creating systemd user session. 186 # Alternatively we could use `machinectl shell`, but it is known not to work well on SELinux-enabled hosts as of April 2020: 187 # https://bugzilla.redhat.com/show_bug.cgi?id=1788616 188 ssh -t -t -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "$HOME/rootless.key" rootless@localhost -- PATH="$PATH" RUNC_USE_SYSTEMD="$RUNC_USE_SYSTEMD" bats -t "$ROOT/tests/integration$ROOTLESS_TESTPATH" 189 else 190 sudo -HE -u rootless PATH="$PATH" "$(which bats)" -t "$ROOT/tests/integration$ROOTLESS_TESTPATH" 191 fi 192 cleanup 193 done