aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/sandbox
diff options
context:
space:
mode:
Diffstat (limited to 'test/sandbox')
-rw-r--r--test/sandbox/main.go409
-rw-r--r--test/sandbox/seccomp.patch18
-rw-r--r--test/sandbox/testdata/device.go134
-rw-r--r--test/sandbox/testdata/mapuid.go124
-rw-r--r--test/sandbox/testdata/pdlike.go141
-rw-r--r--test/sandbox/testdata/simple.go140
-rw-r--r--test/sandbox/testdata/sum.go22
-rw-r--r--test/sandbox/testdata/sum_amd64.go9
-rw-r--r--test/sandbox/testdata/sum_arm64.go9
-rw-r--r--test/sandbox/testdata/testdata.go125
-rw-r--r--test/sandbox/testdata/tty.go145
-rw-r--r--test/sandbox/tester/main.go224
12 files changed, 0 insertions, 1500 deletions
diff --git a/test/sandbox/main.go b/test/sandbox/main.go
deleted file mode 100644
index 4961c04f..00000000
--- a/test/sandbox/main.go
+++ /dev/null
@@ -1,409 +0,0 @@
-//go:build testsuite
-
-// The sandbox test program runs cmd/hakurei with configurations simulating
-// several common workloads and inspects the resulting container states.
-package main
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "io"
- "log"
- "os"
- "os/exec"
- "path/filepath"
- "slices"
- "strconv"
- "strings"
- "sync"
- "sync/atomic"
- "syscall"
-
- "hakurei.app/check"
- "hakurei.app/fhs"
- "hakurei.app/hst"
- "hakurei.app/internal/store"
-
- "hakurei.app/test/internal/testsuite"
- "hakurei.app/test/sandbox/testdata"
-)
-
-// mustScanFor continuously scans the proc filesystem and calls f for each entry
-// visited.
-func mustScanFor(f func(ps *testsuite.StatScanner) bool) int {
- var ps testsuite.StatScanner
-
- for ps.Scan() {
- if f(&ps) {
- break
- }
- }
- if err := ps.Err(); err != nil {
- log.Fatal(err)
- }
- return ps.Stat().PID
-}
-
-// mustStart starts a hakurei container and returns the pid of a process within
-// the container. This process must be terminated by the caller.
-func mustStart(
- ctx context.Context,
- serial uint64,
- cred *syscall.Credential,
- files ...*os.File,
-) (pid int, done <-chan error) {
- _serial := strconv.FormatUint(serial, 10)
- _, done = testsuite.MustStartWith(
- ctx, cred, nil, files,
- "hakurei", "exec",
- "sleep", "infinity", _serial,
- )
-
- var stat syscall.Stat_t
- pid = mustScanFor(func(s *testsuite.StatScanner) bool {
- select {
- case err := <-done:
- if err == nil {
- log.Fatal("test process terminated unexpectedly")
- }
- log.Fatal(err)
- default:
- break
- }
-
- if s.Stat().Comm != "sleep" {
- return false
- }
-
- if args, err := s.Stat().Args(); err != nil {
- if testsuite.IsNotExist(err) {
- return false
- }
- log.Fatal(err)
- } else if !slices.Equal(args, []string{
- "sleep",
- "infinity",
- _serial,
- }) {
- return false
- }
-
- if err := s.Stat().Stat(&stat); err != nil {
- if testsuite.IsNotExist(err) {
- return false
- }
- log.Fatal(err)
- }
-
- id := hst.ToUser[uint32](0, 0)
- if stat.Uid != id || stat.Gid != id {
- return false
- }
-
- return true
- })
- return
-}
-
-func main() {
- go testsuite.ReceiveSignals()
-
- // the signal handler does not wait for termination
- ctx := context.Background()
-
- cred := syscall.Credential{Uid: 1000, Gid: 100}
- if err := os.MkdirAll("/opt/test-helper/bin", 0755); err != nil {
- log.Fatal(err)
- }
-
- var testToolDone <-chan error
- {
- cmd := exec.Command(
- "go", "build",
- "-o", "/opt/test-helper/bin",
- "-tags=tester",
- "-trimpath",
- "./test/sandbox/tester",
- )
- cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
- testToolDone = testsuite.MustStart(cmd)
- }
-
- var wg sync.WaitGroup
- defer wg.Wait()
-
- var serial atomic.Uint64
- newSerial := func() uint64 { serial.Add(1); return serial.Load() }
-
- testsuite.MustRun(
- &cred, nil,
- "hakurei", "exec", "capsh", "--print",
- )
- wg.Go(func() {
- defer log.Println("validated capabilities/securebits in user namespace")
-
- testsuite.MustRun(
- &cred, nil,
- "hakurei", "exec", "capsh", "--has-no-new-privs",
- )
-
- for _, p := range []byte{'a', 'b', 'i', 'p'} {
- testsuite.MustFail(
- &cred, nil,
- "hakurei", "exec", "capsh", "--has-"+string(p)+"=CAP_SYS_ADMIN",
- )
- }
- testsuite.MustFail(
- &cred, nil,
- "hakurei", "exec", "umount", "-R", "/dev",
- )
- })
-
- wg.Go(func() {
- defer log.Println("validated pd seccomp outcome")
-
- c, cancel := context.WithCancel(ctx)
- defer cancel()
-
- pid, done := mustStart(c, newSerial(), &cred)
- testsuite.MustCheckFilter(pid, testdata.SumPD)
- if err := testsuite.FilterTerminated(<-done); err != nil {
- log.Fatal(err)
- }
- })
-
- wg.Go(func() {
- defer log.Println("validated fd leak")
-
- c, cancel := context.WithCancel(ctx)
- defer cancel()
-
- pid, done := mustStart(c, newSerial(), &cred, os.Stdin, os.Stdout, os.Stderr)
- prefix := filepath.Join(fhs.Proc, strconv.Itoa(pid), "fd")
-
- var fail bool
- if entries, err := os.ReadDir(prefix); err != nil {
- log.Fatal(err.Error())
- } else {
- for _, ent := range entries {
- var fd int
- if fd, err = strconv.Atoi(ent.Name()); err != nil {
- log.Fatal(err.Error())
- }
-
- // skip standard streams
- if fd <= 2 {
- continue
- }
- fail = true
-
- var d string
- if d, err = os.Readlink(filepath.Join(
- prefix,
- ent.Name(),
- )); err != nil {
- log.Fatal(err.Error())
- }
- log.Printf("extra fd %d -> %s", fd, d)
- }
- }
- if fail {
- log.Fatal("file descriptors leaked")
- }
-
- if err := syscall.Kill(pid, syscall.SIGTERM); err != nil {
- log.Fatalf("cannot terminate anchor: %v", err)
- } else if err = testsuite.FilterTerminated(<-done); err != nil {
- log.Fatal(err)
- }
- })
-
- if err := os.MkdirAll(testsuite.XDGRuntimeDir, 0700); err != nil {
- log.Fatal(err)
- } else if err = os.Chown(testsuite.XDGRuntimeDir, 1000, 1000); err != nil {
- log.Fatal(err)
- }
-
- var swg sync.WaitGroup
- defer swg.Wait()
- dbusEnv := testsuite.MustStartSessionBus(&cred)
- testsuite.MustStartSway(&swg, &cred, dbusEnv)
- defer testsuite.TerminateSway(&cred)
- testsuite.MustStartPipeWire(&cred, dbusEnv)
-
- if err := <-testToolDone; err != nil {
- log.Fatal(err)
- }
- log.Println("created test helper")
-
- s := store.New(check.MustAbs("/tmp/hakurei.0/state"))
- for name, tc := range testdata.All() {
- wg.Go(func() {
- cmd := exec.Command(
- "script", "/dev/null",
- "-E", "always",
- "-qec",
- "hakurei run "+
- "--identifier-fd=5"+
- " 4 1>&3",
- )
- cmd.SysProcAttr = &syscall.SysProcAttr{
- Pdeathsig: syscall.SIGTERM,
- Credential: &cred,
- }
- var output bytes.Buffer
- cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, &output, &output
- cmd.Env = []string{
- "PATH=" + os.Getenv("PATH"),
- "TERM=xterm",
- testsuite.XDGRuntimeEnv,
- testsuite.WaylandEnv,
- "DISPLAY=:0",
- dbusEnv,
- }
-
- var err error
- var notify, _notify, _conf, conf, ident, _ident *os.File
- if notify, _notify, err = os.Pipe(); err != nil {
- log.Fatal(err)
- }
- cmd.ExtraFiles = append(cmd.ExtraFiles, _notify)
- if _conf, conf, err = os.Pipe(); err != nil {
- log.Fatal(err)
- }
- cmd.ExtraFiles = append(cmd.ExtraFiles, _conf)
- if ident, _ident, err = os.Pipe(); err != nil {
- log.Fatal(err)
- }
- cmd.ExtraFiles = append(cmd.ExtraFiles, _ident)
-
- done := testsuite.MustStart(cmd)
- wg.Go(func() {
- _err := <-done
- log.Printf("completed test case %s\n%s", name, output.String())
- if _err != nil {
- log.Fatalf("test case %s: %v", name, _err)
- }
- })
-
- if err = json.NewEncoder(conf).Encode(&tc.Hakurei); err != nil {
- log.Fatal(err)
- } else if err = conf.Close(); err != nil {
- log.Fatal(err)
- }
-
- var id hst.ID
- if _, err = io.ReadFull(ident, id[:]); err != nil {
- log.Fatal(err)
- } else if err = ident.Close(); err != nil {
- log.Fatal(err)
- }
-
- if _, err = io.ReadFull(notify, make([]byte, 8)); err != nil {
- log.Fatal(err)
- } else if err = notify.Close(); err != nil {
- log.Fatal(err)
- }
-
- var (
- ok bool
- p hst.State
- )
- entries, copyError := s.All()
- for entry := range entries {
- if entry.ID == id {
- ok = true
- if _, err = entry.Load(&p, nil); err != nil {
- log.Fatal(err)
- }
- break
- }
- }
- if err = copyError(); err != nil {
- log.Fatal(err)
- }
- if !ok {
- log.Fatalf("instance %s is not present in store", id)
- }
-
- var stat syscall.Stat_t
- pid := mustScanFor(func(ps *testsuite.StatScanner) bool {
- select {
- case err = <-done:
- if err == nil {
- log.Fatal("test process terminated unexpectedly")
- }
- log.Fatal(err)
- default:
- break
- }
-
- if ps.Stat().Comm != "test-helper" {
- return false
- }
-
- var args []string
- if args, err = ps.Stat().Args(); err != nil {
- if testsuite.IsNotExist(err) {
- return false
- }
- log.Fatal(err)
- } else if !slices.Equal(args, tc.Hakurei.Container.Args) {
- return false
- }
-
- if err = ps.Stat().Stat(&stat); err != nil {
- if testsuite.IsNotExist(err) {
- return false
- }
- log.Fatal(err)
- }
-
- uid := hst.ToUser[uint32](0, uint32(tc.Hakurei.Identity))
- if stat.Uid != uid || stat.Gid != uid {
- return false
- }
-
- var t []byte
- if t, err = os.ReadFile(filepath.Join(
- fhs.Proc,
- strconv.Itoa(ps.Stat().PPID),
- "stat",
- )); err != nil {
- if testsuite.IsNotExist(err) {
- return false
- }
- log.Fatal(err)
- }
-
- var _stat testsuite.Stat
- if err = _stat.UnmarshalText(t); err != nil {
- log.Fatal(err)
- }
- if _stat.PPID != p.ShimPID {
- return false
- }
-
- return true
- })
-
- testsuite.MustCheckFilter(
- pid,
- tc.Sum,
- )
- })
- }
-
- wg.Wait()
-
- if dents, err := os.ReadDir("/tmp"); err != nil {
- log.Fatal(err)
- } else {
- for _, dent := range dents {
- if name := dent.Name(); strings.HasPrefix(name, ".hakurei-shim-") {
- log.Fatalf("leftover shim work dir %q", name)
- }
- }
- }
-}
diff --git a/test/sandbox/seccomp.patch b/test/sandbox/seccomp.patch
deleted file mode 100644
index ddabc71e..00000000
--- a/test/sandbox/seccomp.patch
+++ /dev/null
@@ -1,18 +0,0 @@
-diff --git a/kernel/seccomp.c b/kernel/seccomp.c
-index 25f62867a16d..7b63ccc8daf4 100644
---- a/kernel/seccomp.c
-+++ b/kernel/seccomp.c
-@@ -2216,8 +2216,12 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
- struct seccomp_filter *filter;
- struct sock_fprog_kern *fprog;
- long ret;
-+ struct user_namespace *user_ns = current_user_ns();
-
-- if (!capable(CAP_SYS_ADMIN) ||
-+ if (in_userns(user_ns, task_cred_xxx(task, user_ns))) {
-+ if (!ns_capable(user_ns, CAP_SYS_ADMIN))
-+ return -EACCES;
-+ } else if (!capable(CAP_SYS_ADMIN) ||
- current->seccomp.mode != SECCOMP_MODE_DISABLED) {
- return -EACCES;
- }
diff --git a/test/sandbox/testdata/device.go b/test/sandbox/testdata/device.go
deleted file mode 100644
index 89feb819..00000000
--- a/test/sandbox/testdata/device.go
+++ /dev/null
@@ -1,134 +0,0 @@
-//go:build testsuite || tester
-
-package testdata
-
-import (
- "os"
- "syscall"
-
- "hakurei.app/fhs"
- "hakurei.app/hst"
- "hakurei.app/test/internal/mountinfo"
- "hakurei.app/test/internal/testsuite"
-)
-
-var _ = TestCase{
- Hakurei: hst.Config{
- ID: "app.hakurei.sample.device",
- Enablements: new(hst.EWayland | hst.EPipeWire | hst.EDBus | hst.EX11),
- Identity: 4,
-
- Container: &hst.ContainerConfig{
- Hostname: "hakurei-sample-device",
-
- Filesystem: []hst.FilesystemConfigJSON{
- fcLinker,
- fcLib,
- fcTestHelper,
- },
-
- Username: "u0_a4",
- Shell: fhs.AbsUsrBin.Append("bash"),
- Home: hst.AbsPrivateTmp,
- Path: absTestHelper,
- Args: []string{"tester", "device"},
-
- Flags: hst.FDevice | hst.FShareTmpdir,
- },
- },
-
- // 0, PresetStrict
- Sum: sumSimple,
-
- Env: []string{
- "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus",
- "DISPLAY=unix:/tmp/.X11-unix/X0",
- "HOME=/.hakurei",
- "SHELL=/usr/bin/bash",
- "TERM=xterm",
- "USER=u0_a4",
- "WAYLAND_DISPLAY=wayland-0",
- "XDG_RUNTIME_DIR=/run/user/65534",
- "XDG_SESSION_CLASS=user",
- "XDG_SESSION_TYPE=wayland",
- "PULSE_SERVER=unix:/run/user/65534/pulse/native",
- },
-
- FS: &testsuite.FS{Dir: dir{
- ".hakurei": {Mode: os.ModeDir | 0755, Dir: dir{
- "test-helper": {Mode: 0755},
- }},
-
- // unstable host dev
- "dev": {Mode: os.ModeDir | 0755},
-
- "etc": {Mode: os.ModeDir | 0755, Dir: dir{
- "passwd": {Mode: 0600,
- Data: new("u0_a4:x:65534:65534:Hakurei:/.hakurei:/usr/bin/bash\n")},
- "group": {Mode: 0600,
- Data: new("hakurei:x:65534:\n")},
- }},
-
- "lib64": {Mode: os.ModeDir | 0755, Dir: dir{
- "ld-linux-x86-64.so.2": {Mode: os.ModeSymlink | 0777},
- }},
-
- "run": {Mode: os.ModeDir | 0755, Dir: dir{
- "user": {Mode: os.ModeDir | 0755, Dir: dir{
- "65534": {Mode: os.ModeDir | 0700, Dir: dir{
- "bus": {Mode: os.ModeSocket | 0775},
- "wayland-0": {Mode: os.ModeSocket | 070},
- "pulse": {Mode: os.ModeDir | 0700, Dir: dir{
- "native": {Mode: os.ModeSocket | 0777},
- }},
- }},
- }},
- }},
-
- "tmp": {Mode: os.ModeDir | 0770, Dir: dir{
- ".X11-unix": {Mode: os.ModeDir | 0755, Dir: dir{
- "X0": {Mode: os.ModeSocket | 0775},
- }},
- }},
-
- "lib": {Mode: os.ModeDir | 0755},
- "proc": {Mode: os.ModeDir | 0555},
- }},
-
- Mount: []*mountinfo.Entry{
- r("/sysroot", "/", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110003,gid=110003,inode64"),
- r("/", "/proc", "rw,nosuid,nodev,noexec,relatime", "proc", "proc", "rw"),
- r("/", "/.hakurei", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,size=4k,mode=755,uid=110003,gid=110003,inode64"),
-
- // host /dev in testing environment
- r("/", "/dev", "rw,nosuid", "tmpfs", "tmpfs", ignore),
- r("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,gid=100004,mode=620,ptmxmode=666"),
- r("/", "/dev/mqueue", "rw,nosuid,nodev,noexec,relatime", "mqueue", "mqueue", "rw"),
- r("/kvm", "/dev/kvm", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/fuse", "/dev/fuse", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/", "/dev/shm", "rw,nosuid,nodev,noexec,relatime", "tmpfs", "shm", ignore),
- r("/null", "/dev/null", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/zero", "/dev/zero", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/full", "/dev/full", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/tty", "/dev/tty", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/random", "/dev/random", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/urandom", "/dev/urandom", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
-
- r("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,uid=110003,gid=110003,inode64"),
- r("/", "/run/user", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,size=16384k,mode=755,uid=110003,gid=110003,inode64"),
- r("/tmp/hakurei.0/tmpdir/4", "/tmp", "rw,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/etc/passwd", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110003,gid=110003,inode64"),
- r(ignore, "/etc/group", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110003,gid=110003,inode64"),
- r(ignore, "/run/user/65534/wayland-0", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/tmp/.X11-unix", "/tmp/.X11-unix", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/run/user/65534/bus", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/usr/lib", "/lib", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/opt/test-helper/bin/tester", "/.hakurei/test-helper", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/run/user/65534/pulse/native", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- },
-
- Seccomp: true,
-
- TrySocket: "/tmp/.X11-unix/X0",
- ErrnoAbstract: syscall.ECONNREFUSED,
-}.register("device")
diff --git a/test/sandbox/testdata/mapuid.go b/test/sandbox/testdata/mapuid.go
deleted file mode 100644
index 8dee7b7f..00000000
--- a/test/sandbox/testdata/mapuid.go
+++ /dev/null
@@ -1,124 +0,0 @@
-//go:build testsuite || tester
-
-package testdata
-
-import (
- "os"
- "syscall"
-
- "hakurei.app/fhs"
- "hakurei.app/hst"
- "hakurei.app/test/internal/mountinfo"
- "hakurei.app/test/internal/testsuite"
-)
-
-var _ = TestCase{
- Hakurei: hst.Config{
- ID: "app.hakurei.sample.mapuid",
- Enablements: new(hst.EWayland | hst.EPipeWire | hst.EDBus),
- Identity: 3,
-
- Container: &hst.ContainerConfig{
- Hostname: "hakurei-sample-mapuid",
-
- Filesystem: []hst.FilesystemConfigJSON{
- fcLinker,
- fcLib,
- fcTestHelper,
- },
-
- Username: "u0_a3",
- Shell: fhs.AbsUsrBin.Append("bash"),
- Home: hst.AbsPrivateTmp,
- Path: absTestHelper,
- Args: []string{"tester", "mapuid"},
-
- Flags: hst.FMapRealUID | hst.FShareRuntime | hst.FShareTmpdir,
- },
- },
-
- // 0, PresetStrict
- Sum: sumSimple,
-
- Env: []string{
- "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus",
- "HOME=/.hakurei",
- "SHELL=/usr/bin/bash",
- "TERM=xterm",
- "USER=u0_a3",
- "WAYLAND_DISPLAY=wayland-0",
- "XDG_RUNTIME_DIR=/run/user/1000",
- "XDG_SESSION_CLASS=user",
- "XDG_SESSION_TYPE=wayland",
- "PULSE_SERVER=unix:/run/user/1000/pulse/native",
- },
-
- FS: &testsuite.FS{Dir: dir{
- ".hakurei": {Mode: os.ModeDir | 0755, Dir: dir{
- "test-helper": {Mode: 0755},
- }},
-
- // unstable host dev
- "dev": {Mode: os.ModeDir | 0755},
-
- "etc": {Mode: os.ModeDir | 0755, Dir: dir{
- "passwd": {Mode: 0600,
- Data: new("u0_a3:x:1000:100:Hakurei:/.hakurei:/usr/bin/bash\n")},
- "group": {Mode: 0600,
- Data: new("hakurei:x:100:\n")},
- }},
-
- "lib64": {Mode: os.ModeDir | 0755, Dir: dir{
- "ld-linux-x86-64.so.2": {Mode: os.ModeSymlink | 0777},
- }},
-
- "run": {Mode: os.ModeDir | 0755, Dir: dir{
- "user": {Mode: os.ModeDir | 0755, Dir: dir{
- "1000": {Mode: os.ModeDir | 0770, Dir: dir{
- "bus": {Mode: os.ModeSocket | 0775},
- "wayland-0": {Mode: os.ModeSocket | 070},
- "pulse": {Mode: os.ModeDir | 0700, Dir: dir{
- "native": {Mode: os.ModeSocket | 0777},
- }},
- }},
- }},
- }},
-
- "tmp": {Mode: os.ModeDir | 0770, Dir: dir{}},
-
- "lib": {Mode: os.ModeDir | 0755},
- "proc": {Mode: os.ModeDir | 0555},
- }},
-
- Mount: []*mountinfo.Entry{
- r("/sysroot", "/", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110002,gid=110002,inode64"),
- r("/", "/proc", "rw,nosuid,nodev,noexec,relatime", "proc", "proc", "rw"),
- r("/", "/.hakurei", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,size=4k,mode=755,uid=110002,gid=110002,inode64"),
- r("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", "rw,mode=755,uid=110002,gid=110002,inode64"),
- r("/null", "/dev/null", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/zero", "/dev/zero", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/full", "/dev/full", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/random", "/dev/random", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/urandom", "/dev/urandom", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/tty", "/dev/tty", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"),
- r("/", "/dev/mqueue", "rw,nosuid,nodev,noexec,relatime", "mqueue", "mqueue", "rw"),
- r("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,uid=110002,gid=110002,inode64"),
- r("/", "/run/user", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,size=16384k,mode=755,uid=110002,gid=110002,inode64"),
- r("/tmp/hakurei.0/runtime/3", "/run/user/1000", "rw,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/tmp/hakurei.0/tmpdir/3", "/tmp", "rw,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/etc/passwd", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110002,gid=110002,inode64"),
- r(ignore, "/etc/group", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110002,gid=110002,inode64"),
- r(ignore, "/run/user/1000/wayland-0", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/run/user/1000/bus", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/usr/lib", "/lib", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/opt/test-helper/bin/tester", "/.hakurei/test-helper", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/run/user/1000/pulse/native", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- },
-
- Seccomp: true,
-
- TrySocket: "/tmp/.X11-unix/X0",
- ErrnoAbstract: syscall.ECONNREFUSED,
- ErrnoPathname: syscall.ENOENT,
-}.register("mapuid")
diff --git a/test/sandbox/testdata/pdlike.go b/test/sandbox/testdata/pdlike.go
deleted file mode 100644
index 53d8062a..00000000
--- a/test/sandbox/testdata/pdlike.go
+++ /dev/null
@@ -1,141 +0,0 @@
-//go:build testsuite || tester
-
-package testdata
-
-import (
- "os"
- "syscall"
-
- "hakurei.app/fhs"
- "hakurei.app/hst"
- "hakurei.app/test/internal/mountinfo"
- "hakurei.app/test/internal/testsuite"
-)
-
-var _ = TestCase{
- Hakurei: hst.Config{
- ID: "app.hakurei.sample.pdlike",
- Enablements: new(hst.EWayland | hst.EPipeWire | hst.EDBus),
- Identity: 5,
-
- Container: &hst.ContainerConfig{
- Hostname: "hakurei-sample-pdlike",
-
- Filesystem: []hst.FilesystemConfigJSON{
- fcLinker,
- fcLib,
- fcTestHelper,
- },
-
- Username: "u0_a5",
- Shell: fhs.AbsUsrBin.Append("bash"),
- Home: hst.AbsPrivateTmp,
- Path: absTestHelper,
- Args: []string{"tester", "pdlike"},
-
- Flags: hst.FHostNet | hst.FTty | hst.FUserns | hst.FShareRuntime | hst.FShareTmpdir,
- },
- },
-
- // 0, PresetExt | PresetDenyDevel
- Sum: SumPD,
-
- Env: []string{
- "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus",
- "HOME=/.hakurei",
- "SHELL=/usr/bin/bash",
- "TERM=xterm",
- "USER=u0_a5",
- "WAYLAND_DISPLAY=wayland-0",
- "XDG_RUNTIME_DIR=/run/user/65534",
- "XDG_SESSION_CLASS=user",
- "XDG_SESSION_TYPE=wayland",
- "PULSE_SERVER=unix:/run/user/65534/pulse/native",
- },
-
- FS: &testsuite.FS{Dir: dir{
- ".hakurei": {Mode: os.ModeDir | 0755, Dir: dir{
- "test-helper": {Mode: 0755},
- }},
-
- "dev": {Mode: os.ModeDir | 0755, Dir: dir{
- "core": {Mode: os.ModeSymlink | 0777},
- "fd": {Mode: os.ModeSymlink | 0777},
- "full": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- "mqueue": {Mode: os.ModeDir | os.ModeSticky | 0777, Dir: dir{}},
- "null": {Mode: os.ModeDevice | os.ModeCharDevice | 0666, Data: new("")},
- "ptmx": {Mode: os.ModeSymlink | 0777},
- "pts": {Mode: os.ModeDir | 0755, Dir: dir{
- "ptmx": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- }},
- "random": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- "shm": {Mode: os.ModeDir | os.ModeSticky | 0777, Dir: dir{}},
- "stderr": {Mode: os.ModeSymlink | 0777},
- "stdin": {Mode: os.ModeSymlink | 0777},
- "stdout": {Mode: os.ModeSymlink | 0777},
- "tty": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- "urandom": {Mode: os.ModeDevice | os.ModeCharDevice | 0444},
- "zero": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- }},
-
- "etc": {Mode: os.ModeDir | 0755, Dir: dir{
- "passwd": {Mode: 0600,
- Data: new("u0_a5:x:65534:65534:Hakurei:/.hakurei:/usr/bin/bash\n")},
- "group": {Mode: 0600,
- Data: new("hakurei:x:65534:\n")},
- }},
-
- "lib64": {Mode: os.ModeDir | 0755, Dir: dir{
- "ld-linux-x86-64.so.2": {Mode: os.ModeSymlink | 0777},
- }},
-
- "run": {Mode: os.ModeDir | 0755, Dir: dir{
- "user": {Mode: os.ModeDir | 0755, Dir: dir{
- "65534": {Mode: os.ModeDir | 0770, Dir: dir{
- "bus": {Mode: os.ModeSocket | 0775},
- "wayland-0": {Mode: os.ModeSocket | 070},
- "pulse": {Mode: os.ModeDir | 0700, Dir: dir{
- "native": {Mode: os.ModeSocket | 0777},
- }},
- }},
- }},
- }},
-
- "tmp": {Mode: os.ModeDir | 0770, Dir: dir{}},
-
- "lib": {Mode: os.ModeDir | 0755},
- "proc": {Mode: os.ModeDir | 0555},
- }},
-
- Mount: []*mountinfo.Entry{
- r("/sysroot", "/", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110004,gid=110004,inode64"),
- r("/", "/proc", "rw,nosuid,nodev,noexec,relatime", "proc", "proc", "rw"),
- r("/", "/.hakurei", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,size=4k,mode=755,uid=110004,gid=110004,inode64"),
- r("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", "rw,mode=755,uid=110004,gid=110004,inode64"),
- r("/null", "/dev/null", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/zero", "/dev/zero", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/full", "/dev/full", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/random", "/dev/random", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/urandom", "/dev/urandom", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/tty", "/dev/tty", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"),
- r("/", "/dev/mqueue", "rw,nosuid,nodev,noexec,relatime", "mqueue", "mqueue", "rw"),
- r("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,uid=110004,gid=110004,inode64"),
- r("/", "/run/user", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,size=16384k,mode=755,uid=110004,gid=110004,inode64"),
- r("/tmp/hakurei.0/runtime/5", "/run/user/65534", "rw,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/tmp/hakurei.0/tmpdir/5", "/tmp", "rw,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/etc/passwd", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110004,gid=110004,inode64"),
- r(ignore, "/etc/group", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110004,gid=110004,inode64"),
- r(ignore, "/run/user/65534/wayland-0", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/run/user/65534/bus", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/usr/lib", "/lib", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/opt/test-helper/bin/tester", "/.hakurei/test-helper", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/run/user/65534/pulse/native", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- },
-
- Seccomp: true,
-
- TrySocket: "/tmp/.X11-unix/X0",
- ErrnoAbstract: syscall.EPERM,
- ErrnoPathname: syscall.ENOENT,
-}.register("pdlike")
diff --git a/test/sandbox/testdata/simple.go b/test/sandbox/testdata/simple.go
deleted file mode 100644
index c410e626..00000000
--- a/test/sandbox/testdata/simple.go
+++ /dev/null
@@ -1,140 +0,0 @@
-//go:build testsuite || tester
-
-package testdata
-
-import (
- "os"
- "syscall"
-
- "hakurei.app/fhs"
- "hakurei.app/hst"
- "hakurei.app/test/internal/mountinfo"
- "hakurei.app/test/internal/testsuite"
-)
-
-var _ = TestCase{
- Hakurei: hst.Config{
- ID: "app.hakurei.sample.simple",
- Enablements: new(hst.EWayland | hst.EPipeWire | hst.EDBus),
- Identity: 1,
-
- Container: &hst.ContainerConfig{
- Hostname: "hakurei-sample-simple",
- Env: map[string]string{"HAKUREI_SAMPLE": "1"},
-
- Filesystem: []hst.FilesystemConfigJSON{
- fcLinker,
- fcLib,
- fcTestHelper,
- },
-
- Username: "u0_a1",
- Shell: fhs.AbsUsrBin.Append("bash"),
- Home: hst.AbsPrivateTmp,
- Path: absTestHelper,
- Args: []string{"tester", "simple"},
- },
- },
-
- // 0, PresetStrict
- Sum: sumSimple,
-
- Env: []string{
- "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus",
- "HAKUREI_SAMPLE=1",
- "HOME=/.hakurei",
- "SHELL=/usr/bin/bash",
- "TERM=xterm",
- "USER=u0_a1",
- "WAYLAND_DISPLAY=wayland-0",
- "XDG_RUNTIME_DIR=/run/user/65534",
- "XDG_SESSION_CLASS=user",
- "XDG_SESSION_TYPE=wayland",
- "PULSE_SERVER=unix:/run/user/65534/pulse/native",
- },
-
- FS: &testsuite.FS{Dir: dir{
- ".hakurei": {Mode: os.ModeDir | 0755, Dir: dir{
- "test-helper": {Mode: 0755},
- }},
-
- "dev": {Mode: os.ModeDir | 0755, Dir: dir{
- "core": {Mode: os.ModeSymlink | 0777},
- "fd": {Mode: os.ModeSymlink | 0777},
- "full": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- "mqueue": {Mode: os.ModeDir | os.ModeSticky | 0777, Dir: dir{}},
- "null": {Mode: os.ModeDevice | os.ModeCharDevice | 0666, Data: new("")},
- "ptmx": {Mode: os.ModeSymlink | 0777},
- "pts": {Mode: os.ModeDir | 0755, Dir: dir{
- "ptmx": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- }},
- "random": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- "shm": {Mode: os.ModeDir | os.ModeSticky | 0777, Dir: dir{}},
- "stderr": {Mode: os.ModeSymlink | 0777},
- "stdin": {Mode: os.ModeSymlink | 0777},
- "stdout": {Mode: os.ModeSymlink | 0777},
- "tty": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- "urandom": {Mode: os.ModeDevice | os.ModeCharDevice | 0444},
- "zero": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- }},
-
- "etc": {Mode: os.ModeDir | 0755, Dir: dir{
- "passwd": {Mode: 0600,
- Data: new("u0_a1:x:65534:65534:Hakurei:/.hakurei:/usr/bin/bash\n")},
- "group": {Mode: 0600,
- Data: new("hakurei:x:65534:\n")},
- }},
-
- "lib64": {Mode: os.ModeDir | 0755, Dir: dir{
- "ld-linux-x86-64.so.2": {Mode: os.ModeSymlink | 0777},
- }},
-
- "run": {Mode: os.ModeDir | 0755, Dir: dir{
- "user": {Mode: os.ModeDir | 0755, Dir: dir{
- "65534": {Mode: os.ModeDir | 0700, Dir: dir{
- "bus": {Mode: os.ModeSocket | 0775},
- "wayland-0": {Mode: os.ModeSocket | 070},
- "pulse": {Mode: os.ModeDir | 0700, Dir: dir{
- "native": {Mode: os.ModeSocket | 0777},
- }},
- }},
- }},
- }},
-
- "tmp": {Mode: os.ModeDir | os.ModeSticky | 0777, Dir: dir{}},
-
- "lib": {Mode: os.ModeDir | 0755},
- "proc": {Mode: os.ModeDir | 0555},
- }},
-
- Mount: []*mountinfo.Entry{
- r("/sysroot", "/", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110000,gid=110000,inode64"),
- r("/", "/proc", "rw,nosuid,nodev,noexec,relatime", "proc", "proc", "rw"),
- r("/", "/.hakurei", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,size=4k,mode=755,uid=110000,gid=110000,inode64"),
- r("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", "rw,mode=755,uid=110000,gid=110000,inode64"),
- r("/null", "/dev/null", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/zero", "/dev/zero", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/full", "/dev/full", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/random", "/dev/random", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/urandom", "/dev/urandom", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/tty", "/dev/tty", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"),
- r("/", "/dev/mqueue", "rw,nosuid,nodev,noexec,relatime", "mqueue", "mqueue", "rw"),
- r("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,uid=110000,gid=110000,inode64"),
- r("/", "/run/user", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,size=16384k,mode=755,uid=110000,gid=110000,inode64"),
- r("/", "/tmp", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,uid=110000,gid=110000,inode64"),
- r(ignore, "/etc/passwd", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110000,gid=110000,inode64"),
- r(ignore, "/etc/group", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110000,gid=110000,inode64"),
- r(ignore, "/run/user/65534/wayland-0", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/run/user/65534/bus", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/usr/lib", "/lib", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/opt/test-helper/bin/tester", "/.hakurei/test-helper", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/run/user/65534/pulse/native", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- },
-
- Seccomp: true,
-
- TrySocket: "/tmp/.X11-unix/X0",
- ErrnoAbstract: syscall.ECONNREFUSED,
- ErrnoPathname: syscall.ENOENT,
-}.register("simple")
diff --git a/test/sandbox/testdata/sum.go b/test/sandbox/testdata/sum.go
deleted file mode 100644
index e4e8643a..00000000
--- a/test/sandbox/testdata/sum.go
+++ /dev/null
@@ -1,22 +0,0 @@
-//go:build testsuite || tester
-
-package testdata
-
-import (
- "crypto/sha512"
- "encoding/base64"
- "strconv"
-)
-
-// sum decodes s as [base64.StdEncoding] and panics if it is invalid or
-// unexpectedly sized.
-func sum(s string) [sha512.Size]byte {
- p, err := base64.StdEncoding.DecodeString(s)
- if err != nil {
- panic(err)
- }
- if len(p) != sha512.Size {
- panic("unexpected checksum sized " + strconv.Itoa(len(p)))
- }
- return ([sha512.Size]byte)(p)
-}
diff --git a/test/sandbox/testdata/sum_amd64.go b/test/sandbox/testdata/sum_amd64.go
deleted file mode 100644
index bd751105..00000000
--- a/test/sandbox/testdata/sum_amd64.go
+++ /dev/null
@@ -1,9 +0,0 @@
-//go:build testsuite || tester
-
-package testdata
-
-var (
- SumPD = sum("xpiwgf+Vev4XptlDdFN9N/KmP2+d112nVGVCQHqeMkduvaMxK6d4XX9hhUK8+vJ8on3MLd26hSBp0ovP6MrTmg==")
- sumSimple = sum("6IApjfK9Z1HQBA/CG8DtTAD5XcDXulBsJE2LjPaGbbqO9KMylvKHtmzMwdeOlwJll/hMx97BVz4UiWD701zXNQ==")
- sumTTY = sum("C3YAdHbByeJdv2dMKf32CaFlanAGPkkydlThtTYK09oG4aPjK/gOlhxVFq2D1Lnn6b3odqk3l+J2J9JVXCWFiw==")
-)
diff --git a/test/sandbox/testdata/sum_arm64.go b/test/sandbox/testdata/sum_arm64.go
deleted file mode 100644
index 1691828f..00000000
--- a/test/sandbox/testdata/sum_arm64.go
+++ /dev/null
@@ -1,9 +0,0 @@
-//go:build testsuite || tester
-
-package testdata
-
-var (
- SumPD = sum("QzzpuREoLW3MgCkxn7ebgWtg1aeV7I/JQ0TdAnYU1o8CMWapG7iB+q7u3Sbj2JR04UHlppqX6TuJhMqPFJmZgA==")
- sumSimple = sum("eTGFOKPchRMUtr2W8Q1YYayyqn4Ty43gYZ0PanZwnWfwHvP9Z+GVhisC+XEeW3abxNHrT8DfxBpyPInJaKkylw==")
- sumTTY = sum("zx9NyHQ2uo7JXSaLZjpjl7sLSlrGTYVX5sxSnYsPb2Xa06krYu0p2F7unG3eEmd1ek0PhgMuikXKG86t+jTPXg==")
-)
diff --git a/test/sandbox/testdata/testdata.go b/test/sandbox/testdata/testdata.go
deleted file mode 100644
index 3418d8ae..00000000
--- a/test/sandbox/testdata/testdata.go
+++ /dev/null
@@ -1,125 +0,0 @@
-//go:build testsuite || tester
-
-// Package testdata holds sandbox inspection test cases.
-package testdata
-
-import (
- "crypto/sha512"
- "iter"
- "log"
- "strconv"
- "syscall"
-
- "hakurei.app/check"
- "hakurei.app/fhs"
- "hakurei.app/hst"
- "hakurei.app/test/internal/mountinfo"
- "hakurei.app/test/internal/testsuite"
-)
-
-// A TestCase represents a named test case that may be requested by the caller.
-type TestCase struct {
- // Configuration of the inspected container.
- Hakurei hst.Config
- // Checksum of expected seccomp filter program.
- Sum [sha512.Size]byte
-
- // Expected environment. Skipped if nil.
- Env []string `json:"env,omitempty"`
- // Expected root filesystem. Skipped if nil.
- FS *testsuite.FS `json:"fs,omitempty"`
- // Expected mountinfo records. Skipped if nil.
- Mount []*mountinfo.Entry `json:"mount,omitempty"`
- // Whether to run seccomp checks.
- Seccomp bool `json:"seccomp,omitempty"`
-
- // Name of pathname and abstract sockets to attempt.
- TrySocket string `json:"try_socket,omitempty"`
- // Errno to expect attempting to reach the abstract socket.
- ErrnoAbstract syscall.Errno `json:"errno_abstract,omitempty"`
- // Errno to expect attempting to reach the pathname socket.
- ErrnoPathname syscall.Errno `json:"errno_pathname,omitempty"`
-}
-
-// testCases hold all named test cases.
-var testCases map[string]TestCase
-
-// fc returns c wrapped in its JSON adapter.
-func fc(c hst.FilesystemConfig) hst.FilesystemConfigJSON {
- return hst.FilesystemConfigJSON{
- FilesystemConfig: c,
- }
-}
-
-// ignore is the magic string for a mountinfo field to be ignored.
-const ignore = "//ignore"
-
-type dir = map[string]*testsuite.FS
-
-// r returns the address of a [mountinfo.Entry].
-func r(
- root, target, vfsOptstr string,
- fsType, source, fsOptstr string,
-) *mountinfo.Entry {
- return &mountinfo.Entry{
- ID: -1,
- Parent: -1,
- Root: root,
- Target: target,
- VfsOptstr: vfsOptstr,
- FsType: fsType,
- Source: source,
- FsOptstr: fsOptstr,
- }
-}
-
-var (
- // fcLinker is the dynamic linker symlink.
- fcLinker = fc(&hst.FSLink{
- Target: fhs.AbsRoot.Append("lib64", "ld-linux-x86-64.so.2"),
- Linkname: "../lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",
- })
- // fcLib is the dynamic library bind mount.
- fcLib = fc(&hst.FSBind{Source: fhs.AbsRoot.Append("lib")})
-
- // absTestHelper is the absolute pathname of the test helper program.
- absTestHelper = hst.AbsPrivateTmp.Append("test-helper")
- // fcTestHelper is the test helper bind mount.
- fcTestHelper = fc(&hst.FSBind{
- Target: absTestHelper,
- Source: check.MustAbs("/opt/test-helper/bin/tester"),
- })
-)
-
-// register adds a test case to testCases.
-func (c TestCase) register(name string) (_ struct{}) {
- if testCases == nil {
- testCases = make(map[string]TestCase)
- }
-
- if _, ok := testCases[name]; ok {
- panic("attempting to register " + strconv.Quote(name) + " twice")
- }
- testCases[name] = c
- return
-}
-
-// Get returns the named test case, or terminates the program if name is invalid.
-func Get(name string) TestCase {
- tc, ok := testCases[name]
- if !ok {
- log.Fatalf("invalid test case %q", name)
- }
- return tc
-}
-
-// All returns an iterator over all named test cases.
-func All() iter.Seq2[string, TestCase] {
- return func(yield func(string, TestCase) bool) {
- for name, tc := range testCases {
- if !yield(name, tc) {
- return
- }
- }
- }
-}
diff --git a/test/sandbox/testdata/tty.go b/test/sandbox/testdata/tty.go
deleted file mode 100644
index 4788f484..00000000
--- a/test/sandbox/testdata/tty.go
+++ /dev/null
@@ -1,145 +0,0 @@
-//go:build testsuite || tester
-
-package testdata
-
-import (
- "os"
-
- "hakurei.app/fhs"
- "hakurei.app/hst"
- "hakurei.app/test/internal/mountinfo"
- "hakurei.app/test/internal/testsuite"
-)
-
-var _ = TestCase{
- Hakurei: hst.Config{
- ID: "app.hakurei.sample.tty",
- Enablements: new(hst.EWayland | hst.EPipeWire | hst.EDBus | hst.EX11),
- Identity: 2,
-
- Container: &hst.ContainerConfig{
- Hostname: "hakurei-sample-tty",
-
- Filesystem: []hst.FilesystemConfigJSON{
- fcLinker,
- fcLib,
- fcTestHelper,
- },
-
- Username: "u0_a2",
- Shell: fhs.AbsUsrBin.Append("bash"),
- Home: hst.AbsPrivateTmp,
- Path: absTestHelper,
- Args: []string{"tester", "tty"},
-
- Flags: hst.FHostNet | hst.FHostAbstract |
- hst.FTty | hst.FShareRuntime,
- },
- },
-
- // 0, PresetExt | PresetDenyNS | PresetDenyDevel
- Sum: sumTTY,
-
- Env: []string{
- "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus",
- "DISPLAY=:0",
- "HOME=/.hakurei",
- "SHELL=/usr/bin/bash",
- "TERM=xterm",
- "USER=u0_a2",
- "WAYLAND_DISPLAY=wayland-0",
- "XDG_RUNTIME_DIR=/run/user/65534",
- "XDG_SESSION_CLASS=user",
- "XDG_SESSION_TYPE=wayland",
- "PULSE_SERVER=unix:/run/user/65534/pulse/native",
- },
-
- FS: &testsuite.FS{Dir: dir{
- ".hakurei": {Mode: os.ModeDir | 0755, Dir: dir{
- "test-helper": {Mode: 0755},
- }},
-
- "dev": {Mode: os.ModeDir | 0755, Dir: dir{
- "core": {Mode: os.ModeSymlink | 0777},
- "fd": {Mode: os.ModeSymlink | 0777},
- "full": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- "mqueue": {Mode: os.ModeDir | os.ModeSticky | 0777, Dir: dir{}},
- "null": {Mode: os.ModeDevice | os.ModeCharDevice | 0666, Data: new("")},
- "ptmx": {Mode: os.ModeSymlink | 0777},
- "pts": {Mode: os.ModeDir | 0755, Dir: dir{
- "ptmx": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- }},
- "random": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- "shm": {Mode: os.ModeDir | os.ModeSticky | 0777, Dir: dir{}},
- "stderr": {Mode: os.ModeSymlink | 0777},
- "stdin": {Mode: os.ModeSymlink | 0777},
- "stdout": {Mode: os.ModeSymlink | 0777},
- "tty": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- "urandom": {Mode: os.ModeDevice | os.ModeCharDevice | 0444},
- "zero": {Mode: os.ModeDevice | os.ModeCharDevice | 0666},
- }},
-
- "etc": {Mode: os.ModeDir | 0755, Dir: dir{
- "passwd": {Mode: 0600,
- Data: new("u0_a2:x:65534:65534:Hakurei:/.hakurei:/usr/bin/bash\n")},
- "group": {Mode: 0600,
- Data: new("hakurei:x:65534:\n")},
- }},
-
- "lib64": {Mode: os.ModeDir | 0755, Dir: dir{
- "ld-linux-x86-64.so.2": {Mode: os.ModeSymlink | 0777},
- }},
-
- "run": {Mode: os.ModeDir | 0755, Dir: dir{
- "user": {Mode: os.ModeDir | 0755, Dir: dir{
- "65534": {Mode: os.ModeDir | 0770, Dir: dir{
- "bus": {Mode: os.ModeSocket | 0775},
- "wayland-0": {Mode: os.ModeSocket | 070},
- "pulse": {Mode: os.ModeDir | 0700, Dir: dir{
- "native": {Mode: os.ModeSocket | 0777},
- }},
- }},
- }},
- }},
-
- "tmp": {Mode: os.ModeDir | os.ModeSticky | 0777, Dir: dir{
- ".X11-unix": {Mode: os.ModeDir | 0755, Dir: dir{
- "X0": {Mode: os.ModeSocket | 0775},
- }},
- }},
-
- "lib": {Mode: os.ModeDir | 0755},
- "proc": {Mode: os.ModeDir | 0555},
- }},
-
- Mount: []*mountinfo.Entry{
- r("/sysroot", "/", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110001,gid=110001,inode64"),
- r("/", "/proc", "rw,nosuid,nodev,noexec,relatime", "proc", "proc", "rw"),
- r("/", "/.hakurei", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,size=4k,mode=755,uid=110001,gid=110001,inode64"),
- r("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", "rw,mode=755,uid=110001,gid=110001,inode64"),
- r("/null", "/dev/null", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/zero", "/dev/zero", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/full", "/dev/full", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/random", "/dev/random", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/urandom", "/dev/urandom", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/tty", "/dev/tty", "rw,nosuid,noexec,relatime", "devtmpfs", "devtmpfs", ignore),
- r("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"),
- r("/", "/dev/mqueue", "rw,nosuid,nodev,noexec,relatime", "mqueue", "mqueue", "rw"),
- r("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,uid=110001,gid=110001,inode64"),
- r("/", "/run/user", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,size=16384k,mode=755,uid=110001,gid=110001,inode64"),
- r("/tmp/hakurei.0/runtime/2", "/run/user/65534", "rw,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/", "/tmp", "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", "rw,uid=110001,gid=110001,inode64"),
- r(ignore, "/etc/passwd", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110001,gid=110001,inode64"),
- r(ignore, "/etc/group", "ro,nosuid,nodev,relatime", "tmpfs", "rootfs", "rw,uid=110001,gid=110001,inode64"),
- r(ignore, "/run/user/65534/wayland-0", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/tmp/.X11-unix", "/tmp/.X11-unix", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/run/user/65534/bus", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/usr/lib", "/lib", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r("/opt/test-helper/bin/tester", "/.hakurei/test-helper", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- r(ignore, "/run/user/65534/pulse/native", "ro,nosuid,nodev,relatime", "overlay", "overlay", ignore),
- },
-
- Seccomp: true,
-
- TrySocket: "/tmp/.X11-unix/X0",
-}.register("tty")
diff --git a/test/sandbox/tester/main.go b/test/sandbox/tester/main.go
deleted file mode 100644
index 0782a5e0..00000000
--- a/test/sandbox/tester/main.go
+++ /dev/null
@@ -1,224 +0,0 @@
-//go:build tester
-
-// The sandbox tester runs within a cmd/hakurei container and validates its
-// state. Since the test environment is relatively predictable, the tester can
-// make various assumptions about the host.
-package main
-
-import (
- "errors"
- "log"
- "net"
- "os"
- "os/signal"
- "path/filepath"
- "syscall"
-
- "hakurei.app/test/internal/mountinfo"
- "hakurei.app/test/sandbox/testdata"
-)
-
-//#include <sys/quota.h>
-import "C"
-
-// mustAbs returns s, or terminates the program if s is not absolute.
-func mustAbs(s string) string {
- if !filepath.IsAbs(s) {
- log.Fatalf("%q is not absolute", s)
- }
- return s
-}
-
-func main() {
- log.SetFlags(0)
- log.SetPrefix("tester: ")
-
- if len(os.Args) != 2 {
- log.Fatal("tester requires 1 argument")
- }
- want := testdata.Get(os.Args[1])
- log.SetPrefix("tester: " + os.Args[1] + " ")
-
- checkWritableDirPaths := []string{
- "/dev/shm",
- "/tmp",
- os.Getenv("XDG_RUNTIME_DIR"),
- }
- for _, a := range checkWritableDirPaths {
- pathname := filepath.Join(mustAbs(a), ".hakurei-check")
- if err := os.WriteFile(pathname, make([]byte, 1<<8), 0600); err != nil {
- log.Fatalf("[FAIL] %s", err)
- } else if err = os.Remove(pathname); err != nil {
- log.Fatalf("[FAIL] %s", err)
- } else {
- log.Printf("[ OK ] %s is writable", a)
- }
- }
-
- if want.Env != nil {
- var (
- fail bool
- i int
- got string
- )
- for i, got = range os.Environ() {
- if i == len(want.Env) {
- log.Fatalf("got more than %d environment variables", len(want.Env))
- }
- if got != want.Env[i] {
- fail = true
- log.Printf("[FAIL] %s", got)
- } else {
- log.Printf("[ OK ] %s", got)
- }
- }
-
- i++
- if i != len(want.Env) {
- log.Fatalf("got %d environment variables, want %d", i, len(want.Env))
- }
-
- if fail {
- log.Fatalf("[FAIL] some environment variables did not match")
- }
- } else {
- log.Printf("[SKIP] skipping environ check")
- }
-
- if want.FS != nil {
- if err := want.FS.Compare(log.Printf, ".", os.DirFS("/")); err != nil {
- log.Fatalf("%v", err)
- }
- } else {
- log.Printf("[SKIP] skipping fs check")
- }
-
- if want.Mount != nil {
- var fail bool
-
- m, err := mountinfo.Open("")
- if err != nil {
- log.Fatal(err)
- }
-
- i := 0
- var ent mountinfo.Entry
- for m.Next() {
- m.Copy(&ent)
-
- if i == len(want.Mount) {
- log.Fatalf("got more than %d entries", i)
- }
- if !ent.EqualWithIgnore(want.Mount[i], "//ignore") {
- fail = true
- log.Printf("[FAIL] %s", &ent)
- } else {
- log.Printf("[ OK ] %s", &ent)
- }
-
- i++
- }
- if err = m.Err(); err != nil {
- log.Fatalf("%v", err)
- }
-
- if i != len(want.Mount) {
- log.Fatalf("got %d entries, want %d", i, len(want.Mount))
- }
-
- if fail {
- log.Fatalf("[FAIL] some mount points did not match")
- }
- } else {
- log.Printf("[SKIP] skipping mounts check")
- }
-
- if want.Seccomp {
- const NULL = 0
-
- for _, tc := range []struct {
- name string
- errno syscall.Errno
-
- trap, a1, a2, a3, a4, a5, a6 uintptr
- }{
- {"syslog", syscall.EPERM, syscall.SYS_SYSLOG, 0, NULL, NULL, NULL, NULL, NULL},
- {"acct", syscall.EPERM, syscall.SYS_ACCT, 0, NULL, NULL, NULL, NULL, NULL},
- {"quotactl", syscall.EPERM, syscall.SYS_QUOTACTL, C.Q_GETQUOTA, NULL, uintptr(os.Getuid()), NULL, NULL, NULL},
- {"add_key", syscall.EPERM, syscall.SYS_ADD_KEY, NULL, NULL, NULL, NULL, NULL, NULL},
- {"keyctl", syscall.EPERM, syscall.SYS_KEYCTL, NULL, NULL, NULL, NULL, NULL, NULL},
- {"request_key", syscall.EPERM, syscall.SYS_REQUEST_KEY, NULL, NULL, NULL, NULL, NULL, NULL},
- {"move_pages", syscall.EPERM, syscall.SYS_MOVE_PAGES, uintptr(os.Getpid()), NULL, NULL, NULL, NULL, NULL},
- {"mbind", syscall.EPERM, syscall.SYS_MBIND, NULL, NULL, NULL, NULL, NULL, NULL},
- {"get_mempolicy", syscall.EPERM, syscall.SYS_GET_MEMPOLICY, NULL, NULL, NULL, NULL, NULL, NULL},
- {"set_mempolicy", syscall.EPERM, syscall.SYS_SET_MEMPOLICY, NULL, NULL, NULL, NULL, NULL, NULL},
- {"migrate_pages", syscall.EPERM, syscall.SYS_MIGRATE_PAGES, NULL, NULL, NULL, NULL, NULL, NULL},
- } {
- if _, _, errno := syscall.Syscall6(tc.trap, tc.a1, tc.a2, tc.a3, tc.a4, tc.a5, tc.a6); errno != tc.errno {
- log.Fatalf("[FAIL] %s: %v, want %v", tc.name, errno, tc.errno)
- }
- log.Printf("[ OK ] %s: %v", tc.name, tc.errno)
- }
- } else {
- log.Printf("[SKIP] skipping seccomp check")
- }
-
- if want.TrySocket != "" {
- retry:
- abstractConn, abstractErr := net.Dial("unix", "@"+want.TrySocket)
- pathnameConn, pathnameErr := net.Dial("unix", want.TrySocket)
- ok := true
-
- if abstractErr == nil {
- if err := abstractConn.Close(); err != nil {
- ok = false
- log.Printf("Close: %v", err)
- }
- }
- if pathnameErr == nil {
- if err := pathnameConn.Close(); err != nil {
- ok = false
- log.Printf("Close: %v", err)
- }
- }
-
- if errors.Is(
- abstractErr,
- syscall.EAGAIN,
- ) || errors.Is(
- pathnameErr,
- syscall.EAGAIN,
- ) {
- goto retry
- }
-
- abstractWantErr := error(want.ErrnoAbstract)
- pathnameWantErr := error(want.ErrnoPathname)
- if want.ErrnoAbstract == 0 {
- abstractWantErr = nil
- }
- if want.ErrnoPathname == 0 {
- pathnameWantErr = nil
- }
-
- if !errors.Is(abstractErr, abstractWantErr) {
- ok = false
- log.Printf("abstractErr: %v, want %v", abstractErr, abstractWantErr)
- }
- if !errors.Is(pathnameErr, pathnameWantErr) {
- ok = false
- log.Printf("pathnameErr: %v, want %v", pathnameErr, pathnameWantErr)
- }
-
- if !ok {
- os.Exit(1)
- }
- }
-
- s := make(chan os.Signal, 1)
- signal.Notify(s, syscall.SIGTERM)
- if _, err := os.Stdout.Write(make([]byte, 8)); err != nil {
- log.Fatalf("cannot notify testsuite: %v", err)
- }
- <-s
-}