Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/heimdall

bench/znippy-unpack/enforce.py

#!/usr/bin/env python3
# SPDX-License-Identifier: AGPL-3.0-only
# Heimdall is a defensive sandbox. Enforce the generated znippy-unpack profile on every run
# of its workload: each run in a rootless podman container (heim-m0, the image the binary
# was built in) whose seccomp filter is the checked-in .oci.json plus the two calls crun
# makes after loading a filter (close_range, execve; the probe starts the program itself
# and records from its first instruction). Every run must end with its expect_exit, never
# SIGSYS; then a call outside the profile (znippy compress reads a directory: getdents64)
# must be killed by SIGSYS (exit 159).
#   enforce.py            (from bench/znippy-unpack; TMPDIR for the outputs: ./tmp)
import json, os, shutil, subprocess, sys, tomllib

here = os.path.dirname(os.path.abspath(__file__))
prof = os.path.join(here, "profiles", "znippy-unpack")
w = tomllib.load(open(os.path.join(prof, "workload.toml"), "rb"))
oci = json.load(open(os.path.join(prof, "x86_64-glibc.oci.json")))
oci["syscalls"].append({"names": ["close_range", "execve"], "action": "SCMP_ACT_ALLOW"})
tmp = os.environ.get("ZNIPPY_ENFORCE_TMP", os.path.join(here, "tmp"))
os.makedirs(tmp, exist_ok=True)
filt = os.path.join(tmp, "enforce.oci.json")
json.dump(oci, open(filt, "w"))
corpus = os.path.join(prof, "corpus")
binary = os.path.join(here, "bin", "znippy")
img = os.environ.get("ZNIPPY_ENFORCE_IMAGE", "localhost/nordisk-cargo-toolchain:heim-m0")

def run(name, args):
    t = os.path.join(tmp, "run-" + name)
    shutil.rmtree(t, ignore_errors=True)
    os.makedirs(t)
    args = [a.replace("{corpus}", "/corpus").replace("{tmp}", "/work") for a in args]
    cmd = ["podman", "run", "--rm", "--network", "none", "--security-opt", "seccomp=" + filt,
           "--security-opt", "no-new-privileges", "--cap-drop", "all",
           "-v", corpus + ":/corpus:ro", "-v", t + ":/work", "-v", binary + ":/znippy:ro",
           "-w", "/work", "-e", "RUST_BACKTRACE=0", "--entrypoint", "/znippy", img] + args
    r = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    shutil.rmtree(t, ignore_errors=True)
    return r.returncode

failed = 0
for r in w["run"]:
    want = r.get("expect_exit", 0)
    got = run(r["name"], r["args"])
    ok = got == want
    failed += not ok
    print(f"test znippy-unpack x86_64 glibc {r['name']} ... {'ok' if ok else 'FAILED'} (exit {got}, want {want})", flush=True)
got = run("outside", ["compress", "-i", "/corpus", "-o", "/work/x.znippy", "--format", "generic"])
ok = got == 159
failed += not ok
print(f"test a_call_outside_the_profile_is_killed_by_sigsys ... {'ok' if ok else 'FAILED'} (exit {got}, want 159)")
print(f"\nenforce: {len(w['run']) + 1 - failed} passed; {failed} failed")
sys.exit(1 if failed else 0)