Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

seccompfilter: Use SCMP_ACT_KILL_PROCESS only on compatible kernels #234

Merged
33 changes: 33 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,39 @@ jobs:
steps:
- uses: actions/checkout@v2
- run: DOCKER_BUILDKIT=1 docker build -f Dockerfile.buildtests .
test-centos:
runs-on: macos-latest
env:
LIBSECCOMP_COMMIT: v2.3.3
LIBSLIRP_COMMIT: v4.1.0
Comment on lines +23 to +24
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the VM setup takes approx. twice as much time as an actual build+test, I opted for a single CI job because it seemed more economical. (But it is also just in the realm of 2 min. setup + 1 min. for each run.)

BENCHMARK_IPERF3_DURATION: 3
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably makes sense to not run the full 4 x 60 seconds benchmark in each CI job. I only reduced the time for the duration for the newly added VM-based job.

steps:
- uses: actions/checkout@v2
- name: Setup CentOS 7 VM
run: |
vagrant up --provision --no-tty
cat > ./run-vagrant-tests <<'EOF'
exec vagrant ssh --no-tty -c "
export LIBSECCOMP_COMMIT=\"${LIBSECCOMP_COMMIT}\"
export LIBSLIRP_COMMIT=\"${LIBSLIRP_COMMIT}\"
export BENCHMARK_IPERF3_DURATION=\"${BENCHMARK_IPERF3_DURATION}\"
/src/build-and-test
"
EOF
- name: Build and test with Debian 10's version of libseccomp
run: sh ./run-vagrant-tests
- name: Build and test with Ubuntu 20.04's versions of libseccomp/libslirp
run: sh ./run-vagrant-tests
env:
LIBSECCOMP_COMMIT: v2.4.3
LIBSLIRP_COMMIT: v4.1.0
- name: Build and test with recent versions of libseccomp/libslirp
run: sh ./run-vagrant-tests
env:
LIBSECCOMP_COMMIT: v2.5.0
LIBSLIRP_COMMIT: v4.2.0
# Fails with --disable-dns from libslirp >=4.3.0
# (no timeout in test-slirp4netns-disable-dns.sh).
Comment on lines +50 to +52
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not investigate this further, so can't tell if it's kernel or ncat version related, but with libslirp 4.3.1 the --disable-dns did not show the expected timeout.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

timeout of what?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/rootless-containers/slirp4netns/blob/v1.1.6/tests/test-slirp4netns-disable-dns.sh#L33-L35 does not get a timeout message to grep for (the ncat seems to succeed).

artifact:
runs-on: ubuntu-latest
steps:
Expand Down
8 changes: 4 additions & 4 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ AM_CFLAGS = @GLIB_CFLAGS@ @SLIRP_CFLAGS@ @LIBCAP_CFLAGS@ @LIBSECCOMP_CFLAGS@
noinst_LIBRARIES = libparson.a

AM_TESTS_ENVIRONMENT = PATH="$(abs_top_builddir):$(PATH)"
TESTS = tests/test-slirp4netns.sh tests/test-slirp4netns-configure.sh tests/test-slirp4netns-exit-fd.sh tests/test-slirp4netns-ready-fd.sh tests/test-slirp4netns-api-socket.sh tests/test-slirp4netns-disable-host-loopback.sh tests/test-slirp4netns-cidr.sh tests/test-slirp4netns-outbound-addr.sh tests/test-slirp4netns-disable-dns.sh
TESTS = tests/test-slirp4netns.sh tests/test-slirp4netns-configure.sh tests/test-slirp4netns-exit-fd.sh tests/test-slirp4netns-ready-fd.sh tests/test-slirp4netns-api-socket.sh tests/test-slirp4netns-disable-host-loopback.sh tests/test-slirp4netns-cidr.sh tests/test-slirp4netns-outbound-addr.sh tests/test-slirp4netns-disable-dns.sh tests/test-slirp4netns-seccomp.sh

EXTRA_DIST = \
slirp4netns.1.md \
Expand Down Expand Up @@ -54,12 +54,12 @@ indent:
$(CLANGFORMAT) -i $(slirp4netns_SOURCES)

benchmark:
benchmarks/benchmark-iperf3.sh
benchmarks/benchmark-iperf3-reverse.sh
"$(abs_srcdir)/benchmarks/benchmark-iperf3.sh"
"$(abs_srcdir)/benchmarks/benchmark-iperf3-reverse.sh"

ci:
$(MAKE) indent
git diff --exit-code
git -C "$(abs_srcdir)" diff --exit-code
# TODO: make sure ./vendor is synced with ./vendor.sh
$(MAKE) lint
$(MAKE) -j $(shell nproc) distcheck || ( find . -name test-suite.log | xargs cat; exit 1 )
Expand Down
82 changes: 82 additions & 0 deletions Vagrantfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
Vagrant.configure("2") do |config|
require 'etc'
config.vm.provider "virtualbox" do |vbox|
vbox.cpus = [1, Etc.nprocessors].max
end
config.vm.box = "centos/7"
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder ".", "/src/slirp4netns", type: "rsync"
config.vm.provision "shell",
inline: <<~'SHELL'
set -xeu
sysctl user.max_user_namespaces=65536

yum install -y \
epel-release \
https://repo.ius.io/ius-release-el7.rpm

yum install -y \
autoconf automake make gcc gperf libtool \
git-core meson ninja-build \
glib2-devel libcap-devel \
git-core libtool iproute iputils iperf3 nmap jq

cd /src
chown vagrant .

su vagrant -c '
set -xeu

git clone --depth=1 --no-checkout https://github.com/seccomp/libseccomp
git -C ./libseccomp fetch --tags --depth=1

git clone --depth=1 --no-checkout https://gitlab.freedesktop.org/slirp/libslirp.git
git -C ./libslirp fetch --tags --depth=1

touch ./build-and-test
chmod a+x ./build-and-test
'

cat > ./build-and-test <<'EOS'
Comment on lines +36 to +40
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have only included this static build-and-test script inline here because I wasn't sure if you'd prefer to have the Vagrantfile as self-contained as possible or if a separate script file would be okay/preferable.

#! /bin/sh
set -xeu
src_dir='/src'

prefix="${PREFIX:-${HOME}/prefix}"
build_root="${BUILD_ROOT:-${prefix}/build}"
rm -rf "${prefix}" "${build_root}"
mkdir -p "${build_root}"

export CFLAGS="-I${prefix}"
export LDFLAGS="-L${prefix} -Wl,-rpath,${prefix}/lib"
export PKG_CONFIG_PATH="${prefix}/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}"

git -C "${src_dir}/libseccomp" fetch --depth=1 origin "${LIBSECCOMP_COMMIT:-v2.4.3}"
git -C "${src_dir}/libseccomp" checkout FETCH_HEAD
( cd "${src_dir}/libseccomp" && ./autogen.sh )
mkdir "${build_root}/libseccomp"
pushd "${build_root}/libseccomp"
"${src_dir}/libseccomp/configure" --prefix="${prefix}"
make -j "$( nproc )" CFLAGS+="-I$( pwd )/include"
make install
popd

git -C "${src_dir}/libslirp" fetch --depth=1 origin "${LIBSLIRP_COMMIT:-v4.1.0}"
git -C "${src_dir}/libslirp" checkout FETCH_HEAD
mkdir "${build_root}/libslirp"
pushd "${build_root}/libslirp"
meson setup --prefix="${prefix}" --libdir=lib . "${src_dir}/libslirp"
ninja -C . install
popd

( cd "${src_dir}/slirp4netns" && ./autogen.sh )
mkdir "${build_root}/slirp4netns"
pushd "${build_root}/slirp4netns"
"${src_dir}/slirp4netns/configure" --prefix="${prefix}"
make -j "$( nproc )"

make ci 'CLANGTIDY=echo skipping:' 'CLANGFORMAT=echo skipping:'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not look into how to install clang-tidy/clang-format on CentOS and thus just "disabled" those targets by replacing the command with dummy echos.

popd
EOS
SHELL
end
2 changes: 1 addition & 1 deletion benchmarks/benchmark-iperf3-reverse.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ function cleanup {
}
trap cleanup EXIT

iperf3 -c 127.0.0.1 -p 15201 -t 60
iperf3 -c 127.0.0.1 -p 15201 -t "${BENCHMARK_IPERF3_DURATION:-60}"
2 changes: 1 addition & 1 deletion benchmarks/benchmark-iperf3.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ function cleanup {
}
trap cleanup EXIT

nsenter --preserve-credentials -U -n --target=$child iperf3 -c 10.0.2.2 -t 60
nsenter --preserve-credentials -U -n --target=$child iperf3 -c 10.0.2.2 -t "${BENCHMARK_IPERF3_DURATION:-60}"
3 changes: 2 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ AC_CONFIG_HEADERS([config.h])
AC_PROG_CC
AC_PROG_RANLIB

AM_INIT_AUTOMAKE([1.9 foreign subdir-objects])
AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
AM_PROG_AR

AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/mount.h sys/socket.h sys/timeb.h unistd.h getopt.h])

Expand Down
30 changes: 23 additions & 7 deletions seccompfilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,30 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <linux/seccomp.h>
#include <seccomp.h>
#include "seccomparch.h"

#if defined(SCMP_ACT_KILL_PROCESS) && defined(SECCOMP_GET_ACTION_AVAIL) && \
defined(SECCOMP_RET_KILL_PROCESS)
#include <unistd.h>
#include <sys/syscall.h>

uint32_t get_block_action()
{
const uint32_t action = SECCOMP_RET_KILL_PROCESS;
/* Syscall fails if either actions_avail or kill_process is not available */
if (syscall(__NR_seccomp, SECCOMP_GET_ACTION_AVAIL, 0, &action) == 0)
return SCMP_ACT_KILL_PROCESS;
return SCMP_ACT_KILL;
}
#else
uint32_t get_block_action()
{
return SCMP_ACT_KILL;
}
#endif

int enable_seccomp()
{
int rc = -1, i;
Expand All @@ -24,14 +45,10 @@ int enable_seccomp()
}
}
printf("seccomp: The following syscalls will be blocked by seccomp:");
#ifdef SCMP_ACT_KILL_PROCESS
#define BLOCK_ACTION SCMP_ACT_KILL_PROCESS
#else
#define BLOCK_ACTION SCMP_ACT_KILL
#endif
uint32_t block_action = get_block_action();
#define BLOCK(x) \
{ \
rc = seccomp_rule_add(ctx, BLOCK_ACTION, SCMP_SYS(x), 0); \
rc = seccomp_rule_add(ctx, block_action, SCMP_SYS(x), 0); \
if (rc < 0) \
goto ret; \
printf(" %s", #x); \
Expand Down Expand Up @@ -59,7 +76,6 @@ int enable_seccomp()
BLOCK(umount2);
BLOCK(unshare);
#undef BLOCK
#undef BLOCK_ACTION
printf(".\n");
rc = seccomp_load(ctx);
ret:
Expand Down
4 changes: 2 additions & 2 deletions tests/test-slirp4netns-cidr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ function cleanup {
}
trap cleanup EXIT

ip=$(nsenter --preserve-credentials -U -n --target=$child ip -json a show dev tun11 | jq -r .[1].addr_info[0].local)
[[ $ip = 10.0.135.228 ]]
result="$(nsenter --preserve-credentials -U -n --target=$child ip a show dev tun11)"
echo "$result" | grep -om1 '^\s*inet .*/' | grep -qF 10.0.135.228
Comment on lines +46 to +47
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The older ip on CentOS 7 does not support -json so I had to work around this to make this test runnable on CentOS 7. Please let me know if this needs further adjustment.

23 changes: 23 additions & 0 deletions tests/test-slirp4netns-seccomp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash
set -xeuo pipefail

. $(dirname $0)/common.sh

unshare -r -n sleep infinity &
child=$!

wait_for_network_namespace $child

slirp4netns -c --enable-seccomp --userns-path=/proc/$child/ns/user $child tun11 &
slirp_pid=$!

wait_for_network_device $child tun11

function cleanup {
kill -9 $child $slirp_pid
}
trap cleanup EXIT

nsenter --preserve-credentials -U -n --target=$child ip -a netconf | grep tun11

nsenter --preserve-credentials -U -n --target=$child ip addr show tun11 | grep inet