Skip to content

Commit 57dc492

Browse files
committed
tests/int: use runc features in seccomp flags test
This test (initially added by commit 58ea21d and later amended in commit 26dc55e) currently has two major deficiencies: 1. All possible flag combinations, and their respective numeric values, have to be explicitly listed. Currently we support 3 flags, so there is only 2^3 - 1 = 7 combinations, but adding more flags will become increasingly difficult (for example, 5 flags will result in 31 combinations). 2. The test requires kernel 4.17 (for SECCOMP_FILTER_FLAG_SPEC_ALLOW), and not doing any tests when running on an older kernel. This, too, will make it more difficult to add extra flags in the future. Both issues can be solved by using runc features which now prints all known and supported runc flags. We still have to hardcode the numeric values of all flags, but most of the other work is coded now. In particular: * The test only uses supported flags, meaning it can be used with older kernels, removing the limitation (2) above. * The test calculates the powerset (all possible combinations) of flags and their numeric values. This makes it easier to add more flags, removing the limitation (1) above. * The test will fail (in flags_value) if any new flags will be added to runc but the test itself is not amended. Signed-off-by: Kir Kolyshkin <[email protected]>
1 parent 9d01b2f commit 57dc492

File tree

1 file changed

+54
-16
lines changed

1 file changed

+54
-16
lines changed

tests/integration/seccomp.bats

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,32 @@ function teardown() {
6666
[[ "$output" == *"Network is down"* ]]
6767
}
6868

69-
@test "runc run [seccomp] (SECCOMP_FILTER_FLAG_*)" {
70-
# Linux 4.14: SECCOMP_FILTER_FLAG_LOG
71-
# Linux 4.17: SECCOMP_FILTER_FLAG_SPEC_ALLOW
72-
requires_kernel 4.17
69+
# Prints the numeric value of provided seccomp flags combination.
70+
# The parameter is flags string, as supplied in OCI spec, for example
71+
# '"SECCOMP_FILTER_FLAG_TSYNC","SECCOMP_FILTER_FLAG_LOG"'.
72+
function flags_value() {
73+
# Numeric values of seccomp flags.
74+
declare -A values=(
75+
['"SECCOMP_FILTER_FLAG_TSYNC"']=0 # Supported but ignored by runc, thus 0.
76+
['"SECCOMP_FILTER_FLAG_LOG"']=2
77+
['"SECCOMP_FILTER_FLAG_SPEC_ALLOW"']=4
78+
# XXX: add new values above this line.
79+
)
80+
# Split the flags.
81+
IFS=',' read -ra flags <<<"$1"
82+
83+
local flag v sum=0
84+
for flag in "${flags[@]}"; do
85+
# This will produce "values[$flag]: unbound variable"
86+
# error for a new flag yet unknown to the test.
87+
v=${values[$flag]}
88+
((sum += v)) || true
89+
done
90+
91+
echo $sum
92+
}
7393

94+
@test "runc run [seccomp] (SECCOMP_FILTER_FLAG_*)" {
7495
update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"]
7596
| .process.noNewPrivileges = false
7697
| .linux.seccomp = {
@@ -79,18 +100,35 @@ function teardown() {
79100
"syscalls":[{"names":["mkdir"], "action":"SCMP_ACT_ERRNO"}]
80101
}'
81102

82-
declare -A FLAGS=(
83-
['REMOVE']=4 # No setting, use built-in default.
84-
['EMPTY']=0 # Empty set of flags.
85-
['"SECCOMP_FILTER_FLAG_LOG"']=2
86-
['"SECCOMP_FILTER_FLAG_SPEC_ALLOW"']=4
87-
['"SECCOMP_FILTER_FLAG_TSYNC"']=0 # tsync flag is ignored.
88-
['"SECCOMP_FILTER_FLAG_LOG","SECCOMP_FILTER_FLAG_SPEC_ALLOW"']=6
89-
['"SECCOMP_FILTER_FLAG_LOG","SECCOMP_FILTER_FLAG_TSYNC"']=2
90-
['"SECCOMP_FILTER_FLAG_SPEC_ALLOW","SECCOMP_FILTER_FLAG_TSYNC"']=4
91-
['"SECCOMP_FILTER_FLAG_LOG","SECCOMP_FILTER_FLAG_SPEC_ALLOW","SECCOMP_FILTER_FLAG_TSYNC"']=6
103+
# Get the list of flags supported by runc/seccomp/kernel,
104+
# or "null" if no flags are supported or runc is too old.
105+
mapfile -t flags < <(__runc features | jq -c '.linux.seccomp.supported_flags' |
106+
tr -d '[]\n' | tr ',' '\n')
107+
108+
# This is a set of all possible flag combinations to test.
109+
declare -A TEST_CASES=(
110+
['EMPTY']=0 # Special value: empty set of flags.
111+
['REMOVE']=0 # Special value: no flags set.
92112
)
93-
for key in "${!FLAGS[@]}"; do
113+
114+
# If supported, runc should set SPEC_ALLOW if no flags are set.
115+
if [[ " ${flags[*]} " == *' "SECCOMP_FILTER_FLAG_SPEC_ALLOW" '* ]]; then
116+
TEST_CASES['REMOVE']=$(flags_value '"SECCOMP_FILTER_FLAG_SPEC_ALLOW"')
117+
fi
118+
119+
# Add all possible combinations of seccomp flags
120+
# and their expected numeric values to TEST_CASES.
121+
if [ "${flags[0]}" != "null" ]; then
122+
# Use shell {a,}{b,}{c,} to generate the powerset.
123+
for fc in $(eval echo "$(printf "{'%s,',}" "${flags[@]}")"); do
124+
# Remove the last comma.
125+
fc="${fc/%,/}"
126+
TEST_CASES[$fc]=$(flags_value "$fc")
127+
done
128+
fi
129+
130+
# Finally, run the tests.
131+
for key in "${!TEST_CASES[@]}"; do
94132
case "$key" in
95133
'REMOVE')
96134
update_config ' del(.linux.seccomp.flags)'
@@ -108,7 +146,7 @@ function teardown() {
108146
[[ "$output" == *"mkdir:"*"/dev/shm/foo"*"Operation not permitted"* ]]
109147

110148
# Check the numeric flags value, as printed in the debug log, is as expected.
111-
exp="\"seccomp filter flags: ${FLAGS[$key]}\""
149+
exp="\"seccomp filter flags: ${TEST_CASES[$key]}\""
112150
echo "flags $key, expecting $exp"
113151
[[ "$output" == *"$exp"* ]]
114152
done

0 commit comments

Comments
 (0)