...

Text file src/github.com/opencontainers/runc/tests/rootless.sh

Documentation: github.com/opencontainers/runc/tests

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

View as plain text