1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
# shellcheck disable=SC2235
set -eux
set -o pipefail
# Test cgroup delegation in the unified hierarchy
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
# shellcheck source=test/units/util.sh
. "$(dirname "$0")"/util.sh
if [[ "$(get_cgroup_hierarchy)" != unified ]]; then
echo "Skipping $0 as we're not running with the unified cgroup hierarchy"
exit 0
fi
testcase_controllers() {
systemd-run --wait \
--unit=test-0.service \
--property="DynamicUser=1" \
--property="Delegate=" \
test -w /sys/fs/cgroup/system.slice/test-0.service/ -a \
-w /sys/fs/cgroup/system.slice/test-0.service/cgroup.procs -a \
-w /sys/fs/cgroup/system.slice/test-0.service/cgroup.subtree_control
systemd-run --wait \
--unit=test-1.service \
--property="DynamicUser=1" \
--property="Delegate=memory pids" \
grep -q memory /sys/fs/cgroup/system.slice/test-1.service/cgroup.controllers
systemd-run --wait \
--unit=test-2.service \
--property="DynamicUser=1" \
--property="Delegate=memory pids" \
grep -q pids /sys/fs/cgroup/system.slice/test-2.service/cgroup.controllers
# "io" is not among the controllers enabled by default for all units, verify that
grep -qv io /sys/fs/cgroup/system.slice/cgroup.controllers
# Run a service with "io" enabled, and verify it works
systemd-run --wait \
--unit=test-3.service \
--property="IOAccounting=yes" \
--property="Slice=system-foo-bar-baz.slice" \
grep -q io /sys/fs/cgroup/system.slice/system-foo.slice/system-foo-bar.slice/system-foo-bar-baz.slice/test-3.service/cgroup.controllers
# We want to check if "io" is removed again from the controllers
# list. However, PID 1 (rightfully) does this asynchronously. In order
# to force synchronization on this, let's start a short-lived service
# which requires PID 1 to refresh the cgroup tree, so that we can
# verify that this all works.
systemd-run --wait --unit=test-4.service true
# And now check again, "io" should have vanished
grep -qv io /sys/fs/cgroup/system.slice/cgroup.controllers
}
testcase_attributes() {
# Test if delegation also works for some of the more recent attrs the kernel might or might not support
for attr in cgroup.threads memory.oom.group memory.reclaim ; do
if grep -q "$attr" /sys/kernel/cgroup/delegate ; then
systemd-run --wait \
--unit=test-0.service \
--property="MemoryAccounting=1" \
--property="DynamicUser=1" \
--property="Delegate=" \
test -w /sys/fs/cgroup/system.slice/test-0.service/ -a \
-w /sys/fs/cgroup/system.slice/test-0.service/"$attr"
fi
done
}
testcase_scope_unpriv_delegation() {
# Check that unprivileged delegation works for scopes
useradd test
trap "userdel -r test" RETURN
systemd-run --uid=test \
--property="User=test" \
--property="Delegate=yes" \
--slice workload.slice \
--unit test-workload0.scope\
--scope \
test -w /sys/fs/cgroup/workload.slice/test-workload0.scope -a \
-w /sys/fs/cgroup/workload.slice/test-workload0.scope/cgroup.procs -a \
-w /sys/fs/cgroup/workload.slice/test-workload0.scope/cgroup.subtree_control
}
testcase_user_unpriv_delegation() {
# Check that delegation works for unpriv users, and that we can insert a
# subcgroup owned by a different user (which can happen in case unpriv
# userns where a UID range was delegated), which is still cleaned up
# correctly when it goes down.
run0 -u testuser systemd-run --user \
--property="Delegate=yes" \
--unit=test-chown-subcgroup \
--service-type=exec \
sleep infinity
TESTUID=$(id -u testuser)
CGROUP="/sys/fs/cgroup/user.slice/user-$TESTUID.slice/user@$TESTUID.service/app.slice/test-chown-subcgroup.service"
test -d "$CGROUP"
# Create a subcgroup, and make it owned by some unrelated user
SUBCGROUP="$CGROUP/subcgroup"
mkdir "$SUBCGROUP"
chown 1:1 "$SUBCGROUP"
# Make sure the subcgroup is not empty (empty dirs owned by other users can
# be removed if one owns the dir they are contained in, after all)
mkdir "$SUBCGROUP"/filler
run0 -u testuser systemctl stop --user test-chown-subcgroup.service
# Verify that the subcgroup got correctly removed
(! test -e "$CGROUP")
systemctl stop user@testuser.service
}
testcase_subgroup() {
# Verify that DelegateSubgroup= affects ownership correctly
unit="test-subgroup-$RANDOM.service"
systemd-run --wait \
--unit="$unit" \
--property="DynamicUser=1" \
--property="Delegate=pids" \
--property="DelegateSubgroup=foo" \
test -w "/sys/fs/cgroup/system.slice/$unit" -a \
-w "/sys/fs/cgroup/system.slice/$unit/foo"
# Check that for the subgroup also attributes that aren't covered by
# regular (i.e. main cgroup) delegation ownership rules are delegated properly
if test -f /sys/fs/cgroup/cgroup.max.depth; then
unit="test-subgroup-$RANDOM.service"
systemd-run --wait \
--unit="$unit" \
--property="DynamicUser=1" \
--property="Delegate=pids" \
--property="DelegateSubgroup=zzz" \
test -w "/sys/fs/cgroup/system.slice/$unit/zzz/cgroup.max.depth"
fi
# Check that the invoked process itself is also in the subgroup
unit="test-subgroup-$RANDOM.service"
systemd-run --wait \
--unit="$unit" \
--property="DynamicUser=1" \
--property="Delegate=pids" \
--property="DelegateSubgroup=bar" \
grep -q -x -F "0::/system.slice/$unit/bar" /proc/self/cgroup
}
run_testcases
|