mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
f18e97d312
SCMP_ACT_KILL terminates the process with a fatal signal, which may produce a core dump depending on the host configuration. While this is harmless on ephemeral CI instances, it can leave unwanted core files on developer or customer systems. It also interferes with test environments that detect unexpected core dumps. Signed-off-by: Ricardo Branco <rbranco@suse.de>
203 lines
6.6 KiB
Bash
203 lines
6.6 KiB
Bash
#!/usr/bin/env bats
|
|
|
|
load helpers
|
|
|
|
function setup() {
|
|
setup_busybox
|
|
}
|
|
|
|
function teardown() {
|
|
teardown_bundle
|
|
}
|
|
|
|
@test "runc run [seccomp -ENOSYS handling]" {
|
|
TEST_NAME="seccomp_syscall_test1"
|
|
|
|
# Compile the test binary and update the config to run it.
|
|
gcc -static -o rootfs/seccomp_test "${TESTDATA}/${TEST_NAME}.c"
|
|
update_config ".linux.seccomp = $(<"${TESTDATA}/${TEST_NAME}.json")"
|
|
update_config '.process.args = ["/seccomp_test"]'
|
|
|
|
runc run test_busybox
|
|
[ "$status" -eq 0 ]
|
|
}
|
|
|
|
@test "runc run [seccomp defaultErrnoRet=ENXIO]" {
|
|
TEST_NAME="seccomp_syscall_test2"
|
|
|
|
# Compile the test binary and update the config to run it.
|
|
gcc -static -o rootfs/seccomp_test2 "${TESTDATA}/${TEST_NAME}.c"
|
|
update_config ".linux.seccomp = $(<"${TESTDATA}/${TEST_NAME}.json")"
|
|
update_config '.process.args = ["/seccomp_test2"]'
|
|
|
|
runc run test_busybox
|
|
[ "$status" -eq 0 ]
|
|
}
|
|
|
|
# TODO:
|
|
# - Test other actions like SCMP_ACT_TRAP, SCMP_ACT_TRACE, SCMP_ACT_LOG.
|
|
# - Test args (index, value, valueTwo, etc).
|
|
|
|
@test "runc run [seccomp] (SCMP_ACT_ERRNO default)" {
|
|
update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"]
|
|
| .process.noNewPrivileges = false
|
|
| .linux.seccomp = {
|
|
"defaultAction":"SCMP_ACT_ALLOW",
|
|
"architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"],
|
|
"syscalls":[{"names":["mkdir","mkdirat"], "action":"SCMP_ACT_ERRNO"}]
|
|
}'
|
|
|
|
runc run test_busybox
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *"mkdir:"*"/dev/shm/foo"*"Operation not permitted"* ]]
|
|
}
|
|
|
|
@test "runc run [seccomp] (SCMP_ACT_ERRNO explicit errno)" {
|
|
update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"]
|
|
| .process.noNewPrivileges = false
|
|
| .linux.seccomp = {
|
|
"defaultAction":"SCMP_ACT_ALLOW",
|
|
"architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"],
|
|
"syscalls":[{"names":["mkdir","mkdirat"], "action":"SCMP_ACT_ERRNO", "errnoRet": 100}]
|
|
}'
|
|
|
|
runc run test_busybox
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *"Network is down"* ]]
|
|
}
|
|
|
|
# Prints the numeric value of provided seccomp flags combination.
|
|
# The parameter is flags string, as supplied in OCI spec, for example
|
|
# '"SECCOMP_FILTER_FLAG_TSYNC","SECCOMP_FILTER_FLAG_LOG"'.
|
|
function flags_value() {
|
|
# Numeric values of seccomp flags.
|
|
declare -A values=(
|
|
['"SECCOMP_FILTER_FLAG_TSYNC"']=0 # Supported but ignored by runc, thus 0.
|
|
['"SECCOMP_FILTER_FLAG_LOG"']=2
|
|
['"SECCOMP_FILTER_FLAG_SPEC_ALLOW"']=4
|
|
# XXX: add new values above this line.
|
|
)
|
|
# Split the flags.
|
|
IFS=',' read -ra flags <<<"$1"
|
|
|
|
local flag v sum=0
|
|
for flag in "${flags[@]}"; do
|
|
# This will produce "values[$flag]: unbound variable"
|
|
# error for a new flag yet unknown to the test.
|
|
v=${values[$flag]}
|
|
((sum += v)) || true
|
|
done
|
|
|
|
echo $sum
|
|
}
|
|
|
|
@test "runc run [seccomp] (SECCOMP_FILTER_FLAG_*)" {
|
|
update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"]
|
|
| .process.noNewPrivileges = false
|
|
| .linux.seccomp = {
|
|
"defaultAction":"SCMP_ACT_ALLOW",
|
|
"architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"],
|
|
"syscalls":[{"names":["mkdir", "mkdirat"], "action":"SCMP_ACT_ERRNO"}]
|
|
}'
|
|
|
|
# Get the list of flags supported by runc/seccomp/kernel,
|
|
# or "null" if no flags are supported or runc is too old.
|
|
mapfile -t flags < <(__runc features | jq -c '.linux.seccomp.supportedFlags' |
|
|
tr -d '[]\n' | tr ',' '\n')
|
|
|
|
# This is a set of all possible flag combinations to test.
|
|
declare -A TEST_CASES=(
|
|
['EMPTY']=0 # Special value: empty set of flags.
|
|
['REMOVE']=0 # Special value: no flags set.
|
|
)
|
|
|
|
# If supported, runc should set SPEC_ALLOW if no flags are set.
|
|
if [[ " ${flags[*]} " == *' "SECCOMP_FILTER_FLAG_SPEC_ALLOW" '* ]]; then
|
|
TEST_CASES['REMOVE']=$(flags_value '"SECCOMP_FILTER_FLAG_SPEC_ALLOW"')
|
|
fi
|
|
|
|
# Add all possible combinations of seccomp flags
|
|
# and their expected numeric values to TEST_CASES.
|
|
if [ "${flags[0]}" != "null" ]; then
|
|
# Use shell {a,}{b,}{c,} to generate the powerset.
|
|
for fc in $(eval echo "$(printf "{'%s,',}" "${flags[@]}")"); do
|
|
# Remove the last comma.
|
|
fc="${fc/%,/}"
|
|
TEST_CASES[$fc]=$(flags_value "$fc")
|
|
done
|
|
fi
|
|
|
|
# Finally, run the tests.
|
|
for key in "${!TEST_CASES[@]}"; do
|
|
case "$key" in
|
|
'REMOVE')
|
|
update_config ' del(.linux.seccomp.flags)'
|
|
;;
|
|
'EMPTY')
|
|
update_config ' .linux.seccomp.flags = []'
|
|
;;
|
|
*)
|
|
update_config ' .linux.seccomp.flags = [ '"${key}"' ]'
|
|
;;
|
|
esac
|
|
|
|
runc --debug run test_busybox
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *"mkdir:"*"/dev/shm/foo"*"Operation not permitted"* ]]
|
|
|
|
# Check the numeric flags value, as printed in the debug log, is as expected.
|
|
exp="\"seccomp filter flags: ${TEST_CASES[$key]}\""
|
|
echo "flags $key, expecting $exp"
|
|
[[ "$output" == *"$exp"* ]]
|
|
done
|
|
}
|
|
|
|
@test "runc run [seccomp] (SCMP_ACT_KILL)" {
|
|
update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"]
|
|
| .process.noNewPrivileges = false
|
|
| .process.rlimits = [{"type": "RLIMIT_CORE", "soft": 0, "hard": 0}]
|
|
| .linux.seccomp = {
|
|
"defaultAction":"SCMP_ACT_ALLOW",
|
|
"architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"],
|
|
"syscalls":[{"names":["mkdir","mkdirat"], "action":"SCMP_ACT_KILL"}]
|
|
}'
|
|
|
|
runc run test_busybox
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
# check that a startContainer hook is run with the seccomp filters applied
|
|
@test "runc run [seccomp] (startContainer hook)" {
|
|
update_config ' .process.args = ["/bin/true"]
|
|
| .linux.seccomp = {
|
|
"defaultAction":"SCMP_ACT_ALLOW",
|
|
"architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"],
|
|
"syscalls":[{"names":["mkdir","mkdirat"], "action":"SCMP_ACT_KILL"}]
|
|
}
|
|
| .process.rlimits = [{"type": "RLIMIT_CORE", "soft": 0, "hard": 0}]
|
|
| .hooks = {
|
|
"startContainer": [ {
|
|
"path": "/bin/sh",
|
|
"args": ["sh", "-c", "mkdir /dev/shm/foo"]
|
|
} ]
|
|
}'
|
|
|
|
runc run test_busybox
|
|
[ "$status" -ne 0 ]
|
|
[[ "$output" == *"error running startContainer hook"* ]]
|
|
[[ "$output" == *"bad system call"* ]]
|
|
}
|
|
|
|
@test "runc run [seccomp] (verify syscall compatibility after seccomp enforcement)" {
|
|
update_config ' .process.args = ["true"]
|
|
| .process.noNewPrivileges = false
|
|
| .linux.seccomp = {
|
|
"defaultAction":"SCMP_ACT_ALLOW",
|
|
"architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"],
|
|
"syscalls":[{"names":["close_range", "fsopen", "fsconfig", "fspick", "openat2", "open_tree", "move_mount", "mount_setattr"], "action":"SCMP_ACT_ERRNO", "errnoRet": 38}]
|
|
}'
|
|
|
|
runc run test_busybox
|
|
[ "$status" -eq 0 ]
|
|
}
|