github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/tests/integration/seccomp.bats (about) 1 #!/usr/bin/env bats 2 3 load helpers 4 5 function setup() { 6 setup_busybox 7 } 8 9 function teardown() { 10 teardown_bundle 11 } 12 13 @test "runc run [seccomp -ENOSYS handling]" { 14 TEST_NAME="seccomp_syscall_test1" 15 16 # Compile the test binary and update the config to run it. 17 gcc -static -o rootfs/seccomp_test "${TESTDATA}/${TEST_NAME}.c" 18 update_config ".linux.seccomp = $(<"${TESTDATA}/${TEST_NAME}.json")" 19 update_config '.process.args = ["/seccomp_test"]' 20 21 runc run test_busybox 22 [ "$status" -eq 0 ] 23 } 24 25 @test "runc run [seccomp defaultErrnoRet=ENXIO]" { 26 TEST_NAME="seccomp_syscall_test2" 27 28 # Compile the test binary and update the config to run it. 29 gcc -static -o rootfs/seccomp_test2 "${TESTDATA}/${TEST_NAME}.c" 30 update_config ".linux.seccomp = $(<"${TESTDATA}/${TEST_NAME}.json")" 31 update_config '.process.args = ["/seccomp_test2"]' 32 33 runc run test_busybox 34 [ "$status" -eq 0 ] 35 } 36 37 # TODO: 38 # - Test other actions like SCMP_ACT_TRAP, SCMP_ACT_TRACE, SCMP_ACT_LOG. 39 # - Test args (index, value, valueTwo, etc). 40 41 @test "runc run [seccomp] (SCMP_ACT_ERRNO default)" { 42 update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"] 43 | .process.noNewPrivileges = false 44 | .linux.seccomp = { 45 "defaultAction":"SCMP_ACT_ALLOW", 46 "architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"], 47 "syscalls":[{"names":["mkdir","mkdirat"], "action":"SCMP_ACT_ERRNO"}] 48 }' 49 50 runc run test_busybox 51 [ "$status" -ne 0 ] 52 [[ "$output" == *"mkdir:"*"/dev/shm/foo"*"Operation not permitted"* ]] 53 } 54 55 @test "runc run [seccomp] (SCMP_ACT_ERRNO explicit errno)" { 56 update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"] 57 | .process.noNewPrivileges = false 58 | .linux.seccomp = { 59 "defaultAction":"SCMP_ACT_ALLOW", 60 "architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"], 61 "syscalls":[{"names":["mkdir","mkdirat"], "action":"SCMP_ACT_ERRNO", "errnoRet": 100}] 62 }' 63 64 runc run test_busybox 65 [ "$status" -ne 0 ] 66 [[ "$output" == *"Network is down"* ]] 67 } 68 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 } 93 94 @test "runc run [seccomp] (SECCOMP_FILTER_FLAG_*)" { 95 update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"] 96 | .process.noNewPrivileges = false 97 | .linux.seccomp = { 98 "defaultAction":"SCMP_ACT_ALLOW", 99 "architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"], 100 "syscalls":[{"names":["mkdir", "mkdirat"], "action":"SCMP_ACT_ERRNO"}] 101 }' 102 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.supportedFlags' | 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. 112 ) 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 132 case "$key" in 133 'REMOVE') 134 update_config ' del(.linux.seccomp.flags)' 135 ;; 136 'EMPTY') 137 update_config ' .linux.seccomp.flags = []' 138 ;; 139 *) 140 update_config ' .linux.seccomp.flags = [ '"${key}"' ]' 141 ;; 142 esac 143 144 runc --debug run test_busybox 145 [ "$status" -ne 0 ] 146 [[ "$output" == *"mkdir:"*"/dev/shm/foo"*"Operation not permitted"* ]] 147 148 # Check the numeric flags value, as printed in the debug log, is as expected. 149 exp="\"seccomp filter flags: ${TEST_CASES[$key]}\"" 150 echo "flags $key, expecting $exp" 151 [[ "$output" == *"$exp"* ]] 152 done 153 } 154 155 @test "runc run [seccomp] (SCMP_ACT_KILL)" { 156 update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"] 157 | .process.noNewPrivileges = false 158 | .linux.seccomp = { 159 "defaultAction":"SCMP_ACT_ALLOW", 160 "architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"], 161 "syscalls":[{"names":["mkdir","mkdirat"], "action":"SCMP_ACT_KILL"}] 162 }' 163 164 runc run test_busybox 165 [ "$status" -ne 0 ] 166 } 167 168 # check that a startContainer hook is run with the seccomp filters applied 169 @test "runc run [seccomp] (startContainer hook)" { 170 update_config ' .process.args = ["/bin/true"] 171 | .linux.seccomp = { 172 "defaultAction":"SCMP_ACT_ALLOW", 173 "architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"], 174 "syscalls":[{"names":["mkdir","mkdirat"], "action":"SCMP_ACT_KILL"}] 175 } 176 | .hooks = { 177 "startContainer": [ { 178 "path": "/bin/sh", 179 "args": ["sh", "-c", "mkdir /dev/shm/foo"] 180 } ] 181 }' 182 183 runc run test_busybox 184 [ "$status" -ne 0 ] 185 [[ "$output" == *"error running startContainer hook"* ]] 186 [[ "$output" == *"bad system call"* ]] 187 }