aboutsummaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-03-28 02:24:27 +0900
committerOphestra <cat@gensokyo.uk>2025-03-28 02:24:27 +0900
commitff3cfbb437795c7fee547b8340014071625a61a8 (patch)
tree4e26cf960b815021fc4b96d1ab943adc1a59fb8c /test
parentc13eb70d7dbb73ab2353cc56944c652ea16f9be9 (diff)
test/sandbox: check seccomp outcome
This is as ugly as it is because it has to have CAP_SYS_ADMIN and not be in seccomp mode. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'test')
-rw-r--r--test/configuration.nix3
-rw-r--r--test/sandbox/assert.go31
-rw-r--r--test/sandbox/case/main.go32
-rw-r--r--test/test.py6
4 files changed, 71 insertions, 1 deletions
diff --git a/test/configuration.nix b/test/configuration.nix
index 6f941706..fa1ecca2 100644
--- a/test/configuration.nix
+++ b/test/configuration.nix
@@ -40,6 +40,9 @@ in
# For D-Bus tests:
libnotify
mako
+
+ # For checking seccomp outcome:
+ testCases._testProgram
];
variables = {
diff --git a/test/sandbox/assert.go b/test/sandbox/assert.go
index c4b59fd7..50d078e1 100644
--- a/test/sandbox/assert.go
+++ b/test/sandbox/assert.go
@@ -7,10 +7,14 @@ in the public sandbox/vfs package. Files in this package are excluded by the bui
package sandbox
import (
+ "crypto/sha512"
+ "encoding/hex"
"encoding/json"
+ "errors"
"io/fs"
"log"
"os"
+ "syscall"
)
var (
@@ -124,6 +128,33 @@ func (t *T) MustCheck(want *TestCase) {
}
}
+func MustCheckFilter(pid int, want string) {
+ if err := ptraceAttach(pid); err != nil {
+ fatalf("cannot attach to process %d: %v", pid, err)
+ }
+ buf, err := getFilter[[8]byte](pid, 0)
+ if err0 := ptraceDetach(pid); err0 != nil {
+ printf("cannot detach from process %d: %v", pid, err0)
+ }
+ if err != nil {
+ if errors.Is(err, syscall.ENOENT) {
+ fatalf("seccomp filter not installed for process %d", pid)
+ }
+ fatalf("cannot get filter: %v", err)
+ }
+
+ h := sha512.New()
+ for _, b := range buf {
+ h.Write(b[:])
+ }
+
+ if got := hex.EncodeToString(h.Sum(nil)); got != want {
+ fatalf("[FAIL] %s", got)
+ } else {
+ printf("[ OK ] %s", got)
+ }
+}
+
func mustDecode(wantFilePath string, v any) {
if f, err := os.Open(wantFilePath); err != nil {
fatalf("cannot open %q: %v", wantFilePath, err)
diff --git a/test/sandbox/case/main.go b/test/sandbox/case/main.go
index 59c80efb..4c639b28 100644
--- a/test/sandbox/case/main.go
+++ b/test/sandbox/case/main.go
@@ -1,9 +1,39 @@
package main
import (
+ "log"
"os"
+ "strconv"
+ "strings"
"git.gensokyo.uk/security/fortify/test/sandbox"
)
-func main() { (&sandbox.T{FS: os.DirFS("/")}).MustCheckFile(os.Args[1], "/tmp/sandbox-ok") }
+func main() {
+ log.SetFlags(0)
+ log.SetPrefix("test: ")
+
+ if len(os.Args) < 2 {
+ log.Fatal("invalid argument")
+ }
+
+ switch os.Args[1] {
+ case "filter":
+ if len(os.Args) != 4 {
+ log.Fatal("invalid argument")
+ }
+
+ if pid, err := strconv.Atoi(strings.TrimSpace(os.Args[2])); err != nil {
+ log.Fatalf("%s", err)
+ } else if pid < 1 {
+ log.Fatalf("%d out of range", pid)
+ } else {
+ sandbox.MustCheckFilter(pid, os.Args[3])
+ return
+ }
+
+ default:
+ (&sandbox.T{FS: os.DirFS("/")}).MustCheckFile(os.Args[1], "/tmp/sandbox-ok")
+ return
+ }
+}
diff --git a/test/test.py b/test/test.py
index f0137183..baf074e2 100644
--- a/test/test.py
+++ b/test/test.py
@@ -99,6 +99,12 @@ print(denyOutputVerbose)
# Fail direct fsu call:
print(machine.fail("sudo -u alice -i fsu"))
+# Check seccomp outcome:
+swaymsg("exec fortify run cat")
+pid = int(machine.wait_until_succeeds("pgrep -U 1000000 -x cat", timeout=5))
+print(machine.succeed(f"fortify-test filter {pid} c698b081ff957afe17a6d94374537d37f2a63f6f9dd75da7546542407a9e32476ebda3312ba7785d7f618542bcfaf27ca27dcc2dddba852069d28bcfe8cad39a &>/dev/stdout", timeout=5))
+machine.succeed(f"kill -TERM {pid}")
+
# Verify capabilities/securebits in user namespace:
print(machine.succeed("sudo -u alice -i fortify run capsh --print"))
print(machine.succeed("sudo -u alice -i fortify run capsh --has-no-new-privs"))