From e7880e25b9d400feeaacb82f115fae676ce6c65d Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 21 Oct 2021 17:41:08 +0100
Subject: [PATCH] tests: Add basic test coverage for our seccomp filters

In particular, this checks that CVE-2017-5226, CVE-2019-10063 and
CVE-2021-41133 are still prevented.

Signed-off-by: Simon McVittie <smcv@collabora.com>
(cherry picked from commit 7c5aec474caef7aa004286cc9359611ad21d227b)
(cherry picked from commit ff0f5a15b26dac28c8efd88c8d47e51751df8043)
---
 tests/Makefile-test-matrix.am.inc |  1 +
 tests/Makefile.am.inc             |  1 +
 tests/test-seccomp.sh             | 94 +++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+)
 create mode 100755 tests/test-seccomp.sh

diff --git a/tests/Makefile-test-matrix.am.inc b/tests/Makefile-test-matrix.am.inc
index f56c169e60..e1ec09ffb0 100644
--- a/tests/Makefile-test-matrix.am.inc
+++ b/tests/Makefile-test-matrix.am.inc
@@ -43,6 +43,7 @@ TEST_MATRIX_DIST= \
 	tests/test-override.sh \
 	tests/test-auth.sh \
 	tests/test-unused.sh \
+	tests/test-seccomp.sh \
 	$(NULL)
 TEST_MATRIX_EXTRA_DIST= \
 	tests/test-run.sh \
diff --git a/tests/Makefile.am.inc b/tests/Makefile.am.inc
index 2548080254..fd13c0cd3d 100644
--- a/tests/Makefile.am.inc
+++ b/tests/Makefile.am.inc
@@ -237,6 +237,7 @@ TEST_MATRIX_SOURCE = \
 	tests/test-unused.sh \
 	tests/test-summaries.sh{user+system} \
 	tests/test-subset.sh{user+system} \
+	tests/test-seccomp.sh \
 	$(NULL)
 
 update-test-matrix:
diff --git a/tests/test-seccomp.sh b/tests/test-seccomp.sh
new file mode 100755
index 0000000000..72b0dad231
--- /dev/null
+++ b/tests/test-seccomp.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+# Copyright 2021 Collabora Ltd.
+# SPDX-License-Identifier: LGPL-2.0-or-later
+
+set -euo pipefail
+
+. $(dirname $0)/libtest.sh
+
+skip_without_bwrap
+
+echo "1..16"
+
+setup_repo
+install_repo
+
+cp -a "$G_TEST_BUILDDIR/try-syscall" "$test_tmpdir/try-syscall"
+
+# How this works:
+# try-syscall tries to make various syscalls, some benign, some not.
+#
+# The parameters are chosen to make them fail with EBADF or EFAULT if
+# not blocked. If they are blocked, we get ENOSYS or EPERM. If the syscall
+# is impossible for a particular architecture, we get ENOENT.
+#
+# The exit status is an errno value, which we can compare with the expected
+# errno value.
+
+eval "$("$test_tmpdir/try-syscall" print-errno-values)"
+
+try_syscall () {
+  ${FLATPAK} run \
+    --filesystem="$test_tmpdir" \
+    --command="$test_tmpdir/try-syscall" \
+    $extra_argv \
+    org.test.Hello "$@"
+}
+
+for extra_argv in "" "--allow=multiarch"; do
+  echo "# testing with extra argv: '$extra_argv'"
+
+  echo "# chmod (benign)"
+  e=0
+  try_syscall chmod || e="$?"
+  assert_streq "$e" "$EFAULT"
+  ok "chmod not blocked"
+
+  echo "# chroot (harmful)"
+  e=0
+  try_syscall chroot || e="$?"
+  assert_streq "$e" "$EPERM"
+  ok "chroot blocked with EPERM"
+
+  echo "# clone3 (harmful)"
+  e=0
+  try_syscall clone3 || e="$?"
+  # This is either ENOSYS because the kernel genuinely doesn't implement it,
+  # or because we successfully blocked it. We can't tell which.
+  assert_streq "$e" "$ENOSYS"
+  ok "clone3 blocked with ENOSYS (CVE-2021-41133)"
+
+  echo "# ioctl TIOCNOTTY (benign)"
+  e=0
+  try_syscall "ioctl TIOCNOTTY" || e="$?"
+  assert_streq "$e" "$EBADF"
+  ok "ioctl TIOCNOTTY not blocked"
+
+  echo "# ioctl TIOCSTI (CVE-2017-5226)"
+  e=0
+  try_syscall "ioctl TIOCSTI" || e="$?"
+  assert_streq "$e" "$EPERM"
+  ok "ioctl TIOCSTI blocked (CVE-2017-5226)"
+
+  echo "# ioctl TIOCSTI (trying to repeat CVE-2019-10063)"
+  e=0
+  try_syscall "ioctl TIOCSTI CVE-2019-10063" || e="$?"
+  if test "$e" = "$ENOENT"; then
+    echo "ok # SKIP Cannot replicate CVE-2019-10063 on 32-bit architecture"
+  else
+    assert_streq "$e" "$EPERM"
+    ok "ioctl TIOCSTI with high bits blocked (CVE-2019-10063)"
+  fi
+
+  echo "# listen (benign)"
+  e=0
+  try_syscall "listen" || e="$?"
+  assert_streq "$e" "$EBADF"
+  ok "listen not blocked"
+
+  echo "# prctl (benign)"
+  e=0
+  try_syscall "prctl" || e="$?"
+  assert_streq "$e" "$EFAULT"
+  ok "prctl not blocked"
+done
