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  }