...

Text file src/github.com/opencontainers/runc/tests/integration/seccomp-notify.bats

Documentation: github.com/opencontainers/runc/tests/integration

     1#!/usr/bin/env bats
     2
     3load helpers
     4
     5# Support for seccomp notify requires Linux > 5.6 because
     6# runc uses the pidfd_getfd system call to fetch the seccomp fd.
     7# https://github.com/torvalds/linux/commit/8649c322f75c96e7ced2fec201e123b2b073bf09
     8# We also require arch x86_64, to not make this fail when people run tests
     9# locally on other archs.
    10function setup() {
    11	requires_kernel 5.6
    12	requires arch_x86_64
    13
    14	setup_seccompagent
    15	setup_busybox
    16}
    17
    18function teardown() {
    19	teardown_seccompagent
    20	teardown_bundle
    21}
    22
    23# Create config.json template with SCMP_ACT_NOTIFY actions
    24# $1: command to run
    25# $2: noNewPrivileges (false/true)
    26# $3: list of syscalls
    27function scmp_act_notify_template() {
    28	# The agent intercepts mkdir syscalls and creates the folder appending
    29	# "-bar" (listenerMetadata below) to the name.
    30	update_config '   .process.args = ["/bin/sh", "-c", "'"$1"'"]
    31			| .process.noNewPrivileges = '"$2"'
    32			| .linux.seccomp = {
    33				"defaultAction":"SCMP_ACT_ALLOW",
    34				"listenerPath": "'"$SECCCOMP_AGENT_SOCKET"'",
    35				"listenerMetadata": "bar",
    36				"architectures": [ "SCMP_ARCH_X86","SCMP_ARCH_X32", "SCMP_ARCH_X86_64" ],
    37				"syscalls": [{ "names": ['"$3"'], "action": "SCMP_ACT_NOTIFY" }]
    38			}'
    39}
    40
    41# The call to seccomp is done at different places according to the value of
    42# noNewPrivileges, for this reason many of the following cases are tested with
    43# both values.
    44
    45@test "runc run [seccomp] (SCMP_ACT_NOTIFY noNewPrivileges false)" {
    46	scmp_act_notify_template "mkdir /dev/shm/foo && stat /dev/shm/foo-bar" false '"mkdir"'
    47
    48	runc run test_busybox
    49	[ "$status" -eq 0 ]
    50}
    51
    52@test "runc run [seccomp] (SCMP_ACT_NOTIFY noNewPrivileges true)" {
    53	scmp_act_notify_template "mkdir /dev/shm/foo && stat /dev/shm/foo-bar" true '"mkdir"'
    54
    55	runc run test_busybox
    56	[ "$status" -eq 0 ]
    57}
    58
    59@test "runc exec [seccomp] (SCMP_ACT_NOTIFY noNewPrivileges false)" {
    60	requires root
    61
    62	scmp_act_notify_template "sleep infinity" false '"mkdir"'
    63
    64	runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
    65	[ "$status" -eq 0 ]
    66
    67	runc exec test_busybox /bin/sh -c "mkdir /dev/shm/foo && stat /dev/shm/foo-bar"
    68	[ "$status" -eq 0 ]
    69}
    70
    71@test "runc exec [seccomp] (SCMP_ACT_NOTIFY noNewPrivileges true)" {
    72	requires root
    73
    74	scmp_act_notify_template "sleep infinity" true '"mkdir"'
    75
    76	runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
    77	runc exec test_busybox /bin/sh -c "mkdir /dev/shm/foo && stat /dev/shm/foo-bar"
    78	[ "$status" -eq 0 ]
    79}
    80
    81@test "runc run [seccomp] (SCMP_ACT_NOTIFY important syscalls noNewPrivileges false)" {
    82	scmp_act_notify_template "/bin/true" false '"execve","openat","open","read","close"'
    83
    84	runc run test_busybox
    85	[ "$status" -eq 0 ]
    86}
    87
    88@test "runc run [seccomp] (SCMP_ACT_NOTIFY important syscalls noNewPrivileges true)" {
    89	scmp_act_notify_template "/bin/true" true '"execve","openat","open","read","close"'
    90
    91	runc run test_busybox
    92	[ "$status" -eq 0 ]
    93}
    94
    95@test "runc run [seccomp] (empty listener path)" {
    96	update_config '   .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo && stat /dev/shm/foo"]
    97			| .linux.seccomp = {
    98				"defaultAction":"SCMP_ACT_ALLOW",
    99				"listenerPath": "'"$SECCCOMP_AGENT_SOCKET"'",
   100				"listenerMetadata": "bar",
   101			}'
   102
   103	runc run test_busybox
   104	[ "$status" -eq 0 ]
   105}
   106
   107@test "runc run [seccomp] (SCMP_ACT_NOTIFY empty listener path)" {
   108	scmp_act_notify_template "/bin/true" false '"mkdir"'
   109	update_config '.linux.seccomp.listenerPath = ""'
   110
   111	runc run test_busybox
   112	[ "$status" -ne 0 ]
   113}
   114
   115@test "runc run [seccomp] (SCMP_ACT_NOTIFY wrong listener path)" {
   116	scmp_act_notify_template "/bin/true" false '"mkdir"'
   117	update_config '.linux.seccomp.listenerPath = "/some-non-existing-listener-path.sock"'
   118
   119	runc run test_busybox
   120	[ "$status" -ne 0 ]
   121}
   122
   123@test "runc run [seccomp] (SCMP_ACT_NOTIFY abstract listener path)" {
   124	scmp_act_notify_template "/bin/true" false '"mkdir"'
   125	update_config '.linux.seccomp.listenerPath = "@mysocketishere"'
   126
   127	runc run test_busybox
   128	[ "$status" -ne 0 ]
   129}
   130
   131# Check that killing the seccompagent doesn't block syscalls in
   132# the container. They should return ENOSYS instead.
   133@test "runc run [seccomp] (SCMP_ACT_NOTIFY kill seccompagent)" {
   134	scmp_act_notify_template "sleep 4 && mkdir /dev/shm/foo" false '"mkdir"'
   135
   136	sleep 2 && teardown_seccompagent &
   137	runc run test_busybox
   138	[ "$status" -ne 0 ]
   139	[[ "$output" == *"mkdir:"*"/dev/shm/foo"*"Function not implemented"* ]]
   140}
   141
   142# Check that starting with no seccomp agent running fails with a clear error.
   143@test "runc run [seccomp] (SCMP_ACT_NOTIFY no seccompagent)" {
   144	teardown_seccompagent
   145
   146	scmp_act_notify_template "/bin/true" false '"mkdir"'
   147
   148	runc run test_busybox
   149	[ "$status" -ne 0 ]
   150	[[ "$output" == *"failed to connect with seccomp agent"* ]]
   151}
   152
   153# Check that agent-returned error for the syscall works.
   154@test "runc run [seccomp] (SCMP_ACT_NOTIFY error chmod)" {
   155	scmp_act_notify_template "touch /dev/shm/foo && chmod 777 /dev/shm/foo" false '"chmod", "fchmod", "fchmodat"'
   156
   157	runc run test_busybox
   158	[ "$status" -ne 0 ]
   159	[[ "$output" == *"chmod:"*"/dev/shm/foo"*"No medium found"* ]]
   160}
   161
   162# check that trying to use SCMP_ACT_NOTIFY with write() gives a meaningful error.
   163@test "runc run [seccomp] (SCMP_ACT_NOTIFY write)" {
   164	scmp_act_notify_template "/bin/true" false '"write"'
   165
   166	runc run test_busybox
   167	[ "$status" -ne 0 ]
   168	[[ "$output" == *"SCMP_ACT_NOTIFY cannot be used for the write syscall"* ]]
   169}
   170
   171# check that a startContainer hook doesn't get any extra file descriptor.
   172@test "runc run [seccomp] (SCMP_ACT_NOTIFY startContainer hook)" {
   173	# shellcheck disable=SC2016
   174	# We use single quotes to properly delimit the $1 param to
   175	# update_config(), but this shellshcheck is quite silly and fails if the
   176	# multi-line string includes some $var (even when it is properly outside of the
   177	# single quotes) or when we use this syntax to execute commands in the
   178	# string: $(command).
   179	# So, just disable this check for our usage of update_config().
   180	update_config '   .process.args = ["/bin/true"]
   181			| .linux.seccomp = {
   182				"defaultAction":"SCMP_ACT_ALLOW",
   183				"listenerPath": "'"$SECCCOMP_AGENT_SOCKET"'",
   184				"architectures": [ "SCMP_ARCH_X86", "SCMP_ARCH_X32", "SCMP_ARCH_X86_64" ],
   185				"syscalls":[{ "names": [ "mkdir" ], "action": "SCMP_ACT_NOTIFY" }]
   186			}
   187			|.hooks = {
   188				"startContainer": [ {
   189						"path": "/bin/sh",
   190						"args": [
   191							"sh",
   192							"-c",
   193							"if [ $(ls /proc/self/fd/ | wc -l) -ne 4 ]; then echo \"File descriptors is not 4\". && ls /proc/self/fd/ | wc -l && exit 1; fi"
   194						],
   195				} ]
   196			}'
   197
   198	runc run test_busybox
   199	[ "$status" -eq 0 ]
   200}
   201
   202# Check that example config in the seccomp agent dir works.
   203@test "runc run [seccomp] (SCMP_ACT_NOTIFY example config)" {
   204	# Run the script used in the seccomp agent example.
   205	# This takes a bare config.json and modifies it to run an example.
   206	"${INTEGRATION_ROOT}/../../contrib/cmd/seccompagent/gen-seccomp-example-cfg.sh"
   207
   208	# The listenerPath the previous command uses is the default used by the
   209	# seccomp agent. However, inside bats the socket is in a bats tmp dir.
   210	update_config '.linux.seccomp.listenerPath = "'"$SECCCOMP_AGENT_SOCKET"'"'
   211
   212	runc run test_busybox
   213
   214	[ "$status" -eq 0 ]
   215	[[ "$output" == *"chmod:"*"test-file"*"No medium found"* ]]
   216}

View as plain text