aboutsummaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/flake.nix6
-rw-r--r--test/internal/sandbox/assert.go247
-rw-r--r--test/internal/sandbox/assert_test.go34
-rw-r--r--test/internal/sandbox/seccomp.go46
-rw-r--r--test/internal/testsuite/proc.go23
-rw-r--r--test/internal/testsuite/ptrace.go44
-rw-r--r--test/internal/testsuite/testsuite.go231
-rw-r--r--test/sandbox/case/default.nix97
-rw-r--r--test/sandbox/case/device.nix255
-rw-r--r--test/sandbox/case/mapuid.nix282
-rw-r--r--test/sandbox/case/pd.nix206
-rw-r--r--test/sandbox/case/pdlike.nix277
-rw-r--r--test/sandbox/case/preset.nix274
-rw-r--r--test/sandbox/case/tty.nix288
-rw-r--r--test/sandbox/configuration.nix113
-rw-r--r--test/sandbox/default.nix41
-rw-r--r--test/sandbox/main.go410
-rw-r--r--test/sandbox/seccomp.patch18
-rw-r--r--test/sandbox/test.py88
-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
-rw-r--r--test/sandbox/tool/main.go106
-rw-r--r--test/sandbox/tool/package.nix32
31 files changed, 1771 insertions, 2420 deletions
diff --git a/test/flake.nix b/test/flake.nix
index a73ab03b..9b18c9b6 100644
--- a/test/flake.nix
+++ b/test/flake.nix
@@ -46,12 +46,6 @@
inherit system self;
withRace = true;
};
-
- sandbox = callPackage ./sandbox { inherit self; };
- sandbox-race = callPackage ./sandbox {
- inherit self;
- withRace = true;
- };
}
);
diff --git a/test/internal/sandbox/assert.go b/test/internal/sandbox/assert.go
deleted file mode 100644
index 1194befb..00000000
--- a/test/internal/sandbox/assert.go
+++ /dev/null
@@ -1,247 +0,0 @@
-//go:build testtool
-
-// Package sandbox provides utilities for checking sandbox outcome.
-//
-// This package must never be used outside integration tests, there is a much
-// better native implementation of mountinfo in the public sandbox/vfs package.
-// Files in this package are excluded by the build system to prevent accidental
-// misuse.
-package sandbox
-
-import (
- "encoding/json"
- "errors"
- "io/fs"
- "log"
- "net"
- "os"
- "path/filepath"
- "syscall"
-
- "hakurei.app/test/internal/mountinfo"
- "hakurei.app/test/internal/testsuite"
-)
-
-var (
- assert = log.New(os.Stderr, "sandbox: ", 0)
- printfFunc = assert.Printf
- fatalfFunc = assert.Fatalf
-)
-
-func printf(format string, v ...any) { printfFunc(format, v...) }
-func fatalf(format string, v ...any) { fatalfFunc(format, v...) }
-
-type TestCase struct {
- Env []string `json:"env"`
- FS *testsuite.FS `json:"fs"`
- Mount []*mountinfo.Entry `json:"mount"`
- Seccomp bool `json:"seccomp"`
-
- TrySocket string `json:"try_socket,omitempty"`
- SocketAbstract bool `json:"socket_abstract,omitempty"`
- SocketPathname bool `json:"socket_pathname,omitempty"`
-}
-
-type T struct {
- FS fs.FS
-
- MountsPath string
-}
-
-func (t *T) MustCheckFile(wantFilePath string) {
- var want *TestCase
- mustDecode(wantFilePath, &want)
- t.MustCheck(want)
-}
-
-func mustAbs(s string) string {
- if !filepath.IsAbs(s) {
- fatalf("[FAIL] %q is not absolute", s)
- panic("unreachable")
- }
- return s
-}
-
-func (t *T) MustCheck(want *TestCase) {
- 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 {
- fatalf("[FAIL] %s", err)
- } else if err = os.Remove(pathname); err != nil {
- fatalf("[FAIL] %s", err)
- } else {
- 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) {
- fatalf("got more than %d environment variables", len(want.Env))
- }
- if got != want.Env[i] {
- fail = true
- printf("[FAIL] %s", got)
- } else {
- printf("[ OK ] %s", got)
- }
- }
-
- i++
- if i != len(want.Env) {
- fatalf("got %d environment variables, want %d", i, len(want.Env))
- }
-
- if fail {
- fatalf("[FAIL] some environment variables did not match")
- }
- } else {
- printf("[SKIP] skipping environ check")
- }
-
- if want.FS != nil && t.FS != nil {
- if err := want.FS.Compare(printfFunc, ".", t.FS); err != nil {
- fatalf("%v", err)
- }
- } else {
- printf("[SKIP] skipping fs check")
- }
-
- if want.Mount != nil {
- var fail bool
- m := mustParseMountinfo(t.MountsPath)
- i := 0
- var ent mountinfo.Entry
- for m.Next() {
- m.Copy(&ent)
-
- if i == len(want.Mount) {
- fatalf("got more than %d entries", i)
- }
- if !ent.EqualWithIgnore(want.Mount[i], "//ignore") {
- fail = true
- printf("[FAIL] %s", &ent)
- } else {
- printf("[ OK ] %s", &ent)
- }
-
- i++
- }
- if err := m.Err(); err != nil {
- fatalf("%v", err)
- }
-
- if i != len(want.Mount) {
- fatalf("got %d entries, want %d", i, len(want.Mount))
- }
-
- if fail {
- fatalf("[FAIL] some mount points did not match")
- }
- } else {
- printf("[SKIP] skipping mounts check")
- }
-
- if want.Seccomp {
- if trySyscalls() != nil {
- os.Exit(1)
- }
- } else {
- printf("[SKIP] skipping seccomp check")
- }
-
- if want.TrySocket != "" {
- 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)
- }
- }
-
- abstractWantErr := error(syscall.EPERM)
- pathnameWantErr := error(syscall.ENOENT)
- if want.SocketAbstract {
- abstractWantErr = nil
- }
- if want.SocketPathname {
- 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)
- }
- }
-}
-
-func MustCheckFilter(pid int, want string) {
- err := testsuite.CheckFilter(pid, 0, want)
- if err == nil {
- return
- }
-
- e, ok := errors.AsType[*os.SyscallError](err)
- if !ok {
- fatalf("%s", err)
- }
- switch e.Syscall {
- case "PTRACE_ATTACH":
- fatalf("cannot attach to process %d: %v", pid, err)
- case "PTRACE_SECCOMP_GET_FILTER":
- if errors.Is(e.Err, syscall.ENOENT) {
- fatalf("seccomp filter not installed for process %d", pid)
- }
- fatalf("cannot get filter: %v", err)
- default:
- fatalf("cannot check filter: %v", err)
- }
-
- *(*int)(nil) = 0 // not reached
-}
-
-func mustDecode(wantFilePath string, v any) {
- if f, err := os.Open(wantFilePath); err != nil {
- fatalf("cannot open %q: %v", wantFilePath, err)
- } else if err = json.NewDecoder(f).Decode(v); err != nil {
- fatalf("cannot decode %q: %v", wantFilePath, err)
- } else if err = f.Close(); err != nil {
- fatalf("cannot close %q: %v", wantFilePath, err)
- }
-}
-
-func mustParseMountinfo(name string) *mountinfo.Iter {
- m, err := mountinfo.Open(name)
- if err != nil {
- fatalf("%v", err)
- panic("unreachable")
- }
- return m
-}
diff --git a/test/internal/sandbox/assert_test.go b/test/internal/sandbox/assert_test.go
deleted file mode 100644
index 012ae23d..00000000
--- a/test/internal/sandbox/assert_test.go
+++ /dev/null
@@ -1,34 +0,0 @@
-//go:build testtool
-
-package sandbox
-
-import (
- "encoding/json"
- "os"
- "path/filepath"
- "testing"
-)
-
-type F func(format string, v ...any)
-
-func SwapPrint(f F) (old F) { old = printfFunc; printfFunc = f; return }
-func SwapFatal(f F) (old F) { old = fatalfFunc; fatalfFunc = f; return }
-
-func MustWantFile(t *testing.T, v any) (wantFile string) {
- wantFile = filepath.Join(t.TempDir(), "want.json")
- if f, err := os.OpenFile(wantFile, os.O_CREATE|os.O_WRONLY, 0400); err != nil {
- t.Fatalf("cannot create %q: %v", wantFile, err)
- } else if err = json.NewEncoder(f).Encode(v); err != nil {
- t.Fatalf("cannot encode to %q: %v", wantFile, err)
- } else if err = f.Close(); err != nil {
- t.Fatalf("cannot close %q: %v", wantFile, err)
- }
-
- t.Cleanup(func() {
- if err := os.Remove(wantFile); err != nil {
- t.Fatalf("cannot remove %q: %v", wantFile, err)
- }
- })
-
- return
-}
diff --git a/test/internal/sandbox/seccomp.go b/test/internal/sandbox/seccomp.go
deleted file mode 100644
index 1d8cd457..00000000
--- a/test/internal/sandbox/seccomp.go
+++ /dev/null
@@ -1,46 +0,0 @@
-//go:build testtool
-
-package sandbox
-
-import (
- "os"
- "syscall"
-)
-
-/*
-#include <sys/quota.h>
-*/
-import "C"
-
-const NULL = 0
-
-func trySyscalls() error {
- testCases := []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},
- }
-
- for _, tc := range testCases {
- if _, _, errno := syscall.Syscall6(tc.trap, tc.a1, tc.a2, tc.a3, tc.a4, tc.a5, tc.a6); errno != tc.errno {
- printf("[FAIL] %s: %v, want %v", tc.name, errno, tc.errno)
- return errno
- }
- printf("[ OK ] %s: %v", tc.name, tc.errno)
- }
-
- return nil
-}
diff --git a/test/internal/testsuite/proc.go b/test/internal/testsuite/proc.go
index f2ad8857..e7ef1aed 100644
--- a/test/internal/testsuite/proc.go
+++ b/test/internal/testsuite/proc.go
@@ -10,6 +10,8 @@ import (
"strings"
"syscall"
"unsafe"
+
+ "hakurei.app/fhs"
)
// Stat represents status information read from /proc/pid/stat.
@@ -144,13 +146,9 @@ type Stat struct {
CGuestTime int
}
-// fhsProc points to a virtual kernel file system exposing the process list and
-// other functionality.
-const fhsProc = "/proc/"
-
// Executable is like [os.Executable], but for the process referred to by s.
func (s *Stat) Executable() (string, error) {
- path, err := os.Readlink(filepath.Join(fhsProc, strconv.Itoa(s.PID), "exe"))
+ path, err := os.Readlink(filepath.Join(fhs.Proc, strconv.Itoa(s.PID), "exe"))
// When the executable has been deleted then Readlink returns a
// path appended with " (deleted)".
@@ -159,7 +157,7 @@ func (s *Stat) Executable() (string, error) {
// Stat populates stat with the proc filesystem entry referred to by s.
func (s *Stat) Stat(stat *syscall.Stat_t) (err error) {
- err = syscall.Stat(filepath.Join(fhsProc, strconv.Itoa(s.PID)), stat)
+ err = syscall.Stat(filepath.Join(fhs.Proc, strconv.Itoa(s.PID)), stat)
if err != nil {
err = os.NewSyscallError("stat", err)
}
@@ -168,7 +166,7 @@ func (s *Stat) Stat(stat *syscall.Stat_t) (err error) {
// Args reads arguments of the process referred to by s.
func (s *Stat) Args() ([]string, error) {
- p, err := os.ReadFile(filepath.Join(fhsProc, strconv.Itoa(s.PID), "cmdline"))
+ p, err := os.ReadFile(filepath.Join(fhs.Proc, strconv.Itoa(s.PID), "cmdline"))
if err != nil {
return nil, err
}
@@ -286,6 +284,11 @@ type StatScanner struct {
err error
}
+// IsNotExist returns whether an error is [os.ErrNotExist] or ESRCH.
+func IsNotExist(err error) bool {
+ return errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ESRCH)
+}
+
// Scan reads a process status information entry. It returns false if an
// unrecoverable error is encountered, after which Scan no longer scans new
// entries.
@@ -295,7 +298,7 @@ func (s *StatScanner) Scan() bool {
}
if s.wrapped = s.i == len(s.dents); s.wrapped {
- if s.dents, s.err = os.ReadDir(fhsProc); s.err != nil {
+ if s.dents, s.err = os.ReadDir(fhs.Proc); s.err != nil {
return false
}
s.i = 0
@@ -318,9 +321,9 @@ func (s *StatScanner) Scan() bool {
}
var p []byte
- p, err = os.ReadFile(filepath.Join(fhsProc, dent.Name(), "stat"))
+ p, err = os.ReadFile(filepath.Join(fhs.Proc, dent.Name(), "stat"))
if err != nil {
- if errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ESRCH) {
+ if IsNotExist(err) {
continue
}
s.err = err
diff --git a/test/internal/testsuite/ptrace.go b/test/internal/testsuite/ptrace.go
index 4fcf1508..ccf0900c 100644
--- a/test/internal/testsuite/ptrace.go
+++ b/test/internal/testsuite/ptrace.go
@@ -2,7 +2,7 @@ package testsuite
import (
"crypto/sha512"
- "encoding/hex"
+ "encoding/base64"
"errors"
"fmt"
"os"
@@ -58,10 +58,26 @@ func ptraceAttach(pid int) error {
}
return os.NewSyscallError("wait4", err)
}
- break
- }
+ switch {
+ case status.Stopped():
+ return nil
- return nil
+ case status.Continued():
+ continue
+
+ case status.Signaled():
+ return fmt.Errorf(
+ "tracee terminated by signal %s",
+ status.Signal(),
+ )
+
+ case status.Exited():
+ return fmt.Errorf(
+ "tracee terminated unexpectedly with code %d",
+ status.ExitStatus(),
+ )
+ }
+ }
}
// ptraceDetach detaches from the attached process referred to by pid.
@@ -95,8 +111,8 @@ func getFilter(pid, index int) ([]syscall.SockFilter, error) {
}
// CheckFilter checks the process at pid to have its first filter's contents
-// match the sha512 checksum specified in hexadecimal string representation.
-func CheckFilter(pid, index int, sum string) (err error) {
+// match the specified sha512 checksum.
+func CheckFilter(pid, index int, sum [sha512.Size]byte) (err error) {
if err = ptraceAttach(pid); err != nil {
return
}
@@ -106,15 +122,7 @@ func CheckFilter(pid, index int, sum string) (err error) {
}
}()
- var (
- buf []syscall.SockFilter
- want []byte
- )
-
- if want, err = hex.DecodeString(sum); err != nil {
- return
- }
-
+ var buf []syscall.SockFilter
h := sha512.New()
if buf, err = getFilter(pid, index); err != nil {
return
@@ -125,11 +133,11 @@ func CheckFilter(pid, index int, sum string) (err error) {
))
}
- if got := h.Sum(nil); string(got) != string(want) {
+ if got := h.Sum(nil); string(got) != string(sum[:]) {
return fmt.Errorf(
"bad filter\n\t got: %s\n\twant: %s",
- hex.EncodeToString(got),
- sum,
+ base64.StdEncoding.EncodeToString(got),
+ base64.StdEncoding.EncodeToString(sum[:]),
)
}
return
diff --git a/test/internal/testsuite/testsuite.go b/test/internal/testsuite/testsuite.go
index 6b4cd717..00eb2f92 100644
--- a/test/internal/testsuite/testsuite.go
+++ b/test/internal/testsuite/testsuite.go
@@ -5,12 +5,19 @@
package testsuite
import (
+ "bufio"
+ "context"
+ "crypto/sha512"
+ "errors"
"log"
"os"
"os/exec"
"os/signal"
"os/user"
+ "strconv"
+ "sync"
"syscall"
+ "time"
)
// ReceiveSignals blocks until a termination signal arrives, and terminates.
@@ -39,7 +46,231 @@ func MustRun(command ...string) {
}
}
+// ErrUnexpectedSuccess is returned for processes expected to exit with a
+// non-zero code, but failed to do so.
+var ErrUnexpectedSuccess = errors.New("process unexpectedly exited with code 0")
+
+// MustFail runs command and terminates the testsuite if the program fails to
+// start or exits with code 0.
+func MustFail(command ...string) {
+ cmd := exec.Command(command[0], command[1:]...)
+ cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
+ if err := cmd.Run(); err == nil {
+ log.Fatal(ErrUnexpectedSuccess)
+ } else if e, ok := errors.AsType[*exec.ExitError](err); !ok {
+ log.Fatal(err)
+ } else if !e.Exited() {
+ log.Fatal(e)
+ }
+}
+
// MustRunAs wraps [MustRun] for sudo.
func MustRunAs(username string, command ...string) {
MustRun(append([]string{"sudo", "-u", username}, command...)...)
}
+
+// MustFailAs wraps [MustFail] for sudo.
+func MustFailAs(username string, command ...string) {
+ MustFail(append([]string{"sudo", "-u", username}, command...)...)
+}
+
+// MustStart starts cmd and returns a channel delivering its wait error.
+func MustStart(cmd *exec.Cmd) (done <-chan error) {
+ if err := cmd.Start(); err != nil {
+ log.Fatal(err)
+ }
+ d := make(chan error)
+ go func() { d <- cmd.Wait() }()
+ return d
+}
+
+// MustStartAs wraps [MustStart] for sudo.
+func MustStartAs(
+ ctx context.Context,
+ username string,
+ files []*os.File,
+ command ...string,
+) (proc *os.Process, done <-chan error) {
+ sudoArgs := []string{
+ "-u", username,
+ }
+ if len(files) != 0 {
+ sudoArgs = append(sudoArgs, "-C", strconv.Itoa(len(files)+4))
+ }
+ sudoArgs = append(sudoArgs, "--")
+ cmd := exec.CommandContext(ctx, "sudo", append(sudoArgs, command...)...)
+ cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
+ cmd.ExtraFiles = files
+ cmd.SysProcAttr = &syscall.SysProcAttr{Pdeathsig: syscall.SIGTERM}
+ return cmd.Process, MustStart(cmd)
+}
+
+// MustCheckFilter is like [CheckFilter], but terminates the test suite if a
+// non-nil error is returned. Otherwise, the tracee is terminated after it
+// resumes.
+func MustCheckFilter(pid int, sum [sha512.Size]byte) {
+ // podman installs its own filter
+ if err := CheckFilter(pid, 1, sum); err != nil {
+ log.Fatal(err)
+ } else if err = syscall.Kill(pid, syscall.SIGTERM); err != nil {
+ log.Fatalf("cannot terminate tracee: %v", err)
+ }
+}
+
+// FilterTerminated returns a non-nil error if err is not an [exec.ExitError]
+// describing a process terminated by a syscall.SIGTERM signal.
+func FilterTerminated(err error) error {
+ if err == nil {
+ return ErrUnexpectedSuccess
+ }
+
+ e, ok := errors.AsType[*exec.ExitError](err)
+ if !ok {
+ return err
+ }
+
+ if e.ExitCode() == 0x80+int(syscall.SIGTERM) {
+ return nil
+ }
+ return e
+}
+
+// Poll repeatedly runs command until it succeeds.
+func Poll(d time.Duration, command ...string) {
+ for range time.NewTicker(d).C {
+ cmd := exec.Command(command[0], command[1:]...)
+ if err := cmd.Run(); err != nil {
+ if e, ok := errors.AsType[*exec.ExitError](err); ok && e.Exited() {
+ continue
+ }
+ log.Fatal(err)
+ }
+ break
+ }
+}
+
+const (
+ // XDGRuntimeDir is the hardcoded XDG runtime directory for the user
+ // described by [GetUser].
+ XDGRuntimeDir = "/var/run/user/1000"
+
+ // XDGRuntimeEnv is the environment variable string for XDG_RUNTIME_DIR.
+ XDGRuntimeEnv = "XDG_RUNTIME_DIR=" + XDGRuntimeDir
+)
+
+// MustStartSessionBus starts a session bus that is never explicitly terminated.
+// The test suite is terminated if the session bus daemon terminates.
+func MustStartSessionBus(username string) (dbusEnv string) {
+ r, w, err := os.Pipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // this is never explicitly terminated
+ _, done := MustStartAs(
+ context.Background(), username, []*os.File{w},
+ "dbus-daemon",
+ "--print-address=3",
+ "--address=unix:path="+XDGRuntimeDir+"/dbus",
+ "--session",
+ "--nofork",
+ "--nopidfile",
+ )
+
+ go func() {
+ if _err := <-done; _err != nil {
+ log.Fatal(_err)
+ }
+ log.Fatal("session bus terminated unexpectedly")
+ }()
+
+ dbusEnv, err = bufio.NewReader(r).ReadString('\n')
+ if err != nil {
+ log.Fatal(err)
+ }
+ dbusEnv = dbusEnv[:len(dbusEnv)-1]
+ log.Printf("dbus listening on %s", dbusEnv)
+ dbusEnv = "DBUS_SESSION_BUS_ADDRESS=" + dbusEnv
+
+ if err = r.Close(); err != nil {
+ log.Fatal(err)
+ }
+ return
+}
+
+const (
+ // SwayEnv is the environment variable string for the sway IPC socket.
+ SwayEnv = "SWAYSOCK=" + XDGRuntimeDir + "/sway"
+ // WaylandEnv is the environment variable string for the wayland display.
+ WaylandEnv = "WAYLAND_DISPLAY=wayland-1"
+)
+
+// MustStartSway starts the sway wayland display server which must be terminated
+// by calling [TerminateSway].
+func MustStartSway(
+ wg *sync.WaitGroup,
+ username, dbusEnv string,
+) {
+ wg.Go(func() {
+ // this is terminated via swaymsg
+ _, done := MustStartAs(
+ context.Background(), username, nil, "env",
+ "WLR_BACKENDS=headless",
+ XDGRuntimeEnv,
+ SwayEnv,
+ dbusEnv,
+ "sway",
+ )
+ if err := <-done; err != nil {
+ log.Fatal(err)
+ }
+ })
+
+ Poll(50*time.Millisecond, "sudo", "-u", username, SwayEnv, "swaymsg")
+ log.Printf("sway available via %s", SwayEnv)
+}
+
+// TerminateSway requests for the sway server to terminate via sway IPC.
+func TerminateSway(username string) {
+ MustFailAs(username, SwayEnv, "swaymsg", "exit")
+}
+
+// MustStartPipeWire starts a PipeWire server that is never explicitly
+// terminated. The test suite is terminated if the PipeWire server terminates.
+func MustStartPipeWire(username, dbusEnv string) {
+ // this is never explicitly terminated
+ _, done := MustStartAs(
+ context.Background(), username, nil, "env",
+ XDGRuntimeEnv,
+ dbusEnv,
+ "pipewire",
+ )
+
+ go func() {
+ if _err := <-done; _err != nil {
+ log.Fatal(_err)
+ }
+ log.Fatal("pipewire terminated unexpectedly")
+ }()
+
+ Poll(50*time.Millisecond, "sudo", "-u", username,
+ XDGRuntimeEnv,
+ dbusEnv,
+ "wpctl",
+ "status",
+ )
+
+ _, _done := MustStartAs(
+ context.Background(), username, nil, "env",
+ XDGRuntimeEnv,
+ dbusEnv,
+ "wireplumber",
+ )
+
+ go func() {
+ if _err := <-_done; _err != nil {
+ log.Fatal(_err)
+ }
+ log.Fatal("wireplumber terminated unexpectedly")
+ }()
+}
diff --git a/test/sandbox/case/default.nix b/test/sandbox/case/default.nix
deleted file mode 100644
index 337f4bf2..00000000
--- a/test/sandbox/case/default.nix
+++ /dev/null
@@ -1,97 +0,0 @@
-system: lib: testProgram:
-let
- fs = mode: dir: data: {
- mode = lib.fromHexString mode;
- inherit
- dir
- data
- ;
- };
-
- ignore = "//ignore";
-
- ent = root: target: vfs_optstr: fstype: source: fs_optstr: {
- id = -1;
- parent = -1;
- inherit
- root
- target
- vfs_optstr
- fstype
- source
- fs_optstr
- ;
- };
-
- importTestCase =
- path:
- import path {
- inherit
- fs
- ent
- ignore
- system
- ;
- };
-
- callTestCase =
- path: identity:
- let
- tc = importTestCase path;
- in
- {
- name = "check-sandbox-${tc.name}";
- inherit identity;
- verbose = true;
- inherit (tc)
- tty
- device
- mapRealUid
- useCommonPaths
- userns
- hostAbstract
- shareRuntime
- shareTmpdir
- ;
- enablements = {
- inherit (tc) x11;
- };
- share = testProgram;
- packages = [ ];
- path = "${testProgram}/bin/hakurei-test";
- args = [
- "hakurei-test"
- "-p"
- "/var/tmp/.hakurei-check-ok.${toString identity}"
- "-t"
- (toString (builtins.toFile "hakurei-${tc.name}-want.json" (builtins.toJSON tc.want)))
- "-s"
- tc.expectedFilter.${system}
- ];
-
- extraPaths =
- if tc.useCommonPaths then
- [ ]
- else
- [
- {
- type = "bind";
- src = "/var/tmp";
- write = true;
- }
- ];
- };
-
- testCaseName = name: "cat.gensokyo.hakurei.test." + name;
-in
-{
- apps = {
- ${testCaseName "preset"} = callTestCase ./preset.nix 1;
- ${testCaseName "tty"} = callTestCase ./tty.nix 2;
- ${testCaseName "mapuid"} = callTestCase ./mapuid.nix 3;
- ${testCaseName "device"} = callTestCase ./device.nix 4;
- ${testCaseName "pdlike"} = callTestCase ./pdlike.nix 5;
- };
-
- pd = importTestCase ./pd.nix;
-}
diff --git a/test/sandbox/case/device.nix b/test/sandbox/case/device.nix
deleted file mode 100644
index 889e0a06..00000000
--- a/test/sandbox/case/device.nix
+++ /dev/null
@@ -1,255 +0,0 @@
-{
- fs,
- ent,
- ignore,
- system,
-}:
-let
- extraPaths = {
- x86_64-linux = {
- fd = "fd0";
- sr = {
- sr0 = fs "80001ff" null null;
- };
- };
- aarch64-linux = {
- fd = "mtdblock0";
- sr = { };
- };
- };
-in
-{
- name = "device";
- tty = false;
- device = true;
- mapRealUid = false;
- useCommonPaths = true;
- userns = false;
- x11 = true;
- hostAbstract = false;
- shareRuntime = false;
- shareTmpdir = true;
-
- # 0, PresetStrict
- expectedFilter = {
- x86_64-linux = "e880298df2bd6751d0040fc21bc0ed4c00f95dc0d7ba506c244d8b8cf6866dba8ef4a33296f287b66cccc1d78e97026597f84cc7dec1573e148960fbd35cd735";
- aarch64-linux = "79318538a3dc851314b6bd96f10d5861acb2aa7e13cb8de0619d0f6a76709d67f01ef3fd67e195862b02f9711e5b769bc4d1eb4fc0dfc41a723c89c968a93297";
- };
-
- want = {
- env = [
- "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus"
- "DISPLAY=unix:/tmp/.X11-unix/X0"
- "HOME=/var/lib/hakurei/u0/a4"
- "SHELL=/run/current-system/sw/bin/bash"
- "TERM=linux"
- "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 = fs "dead" {
- ".hakurei" = fs "800001ed" {
- ".ro-store" = fs "801001fd" null null;
- store = fs "800001ff" null null;
- } null;
- bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
- dev = fs "800001ed" null null;
- etc = fs "800001ed" {
- ".clean" = fs "80001ff" null null;
- ".host" = fs "800001c0" null null;
- ".updated" = fs "80001ff" null null;
- "NIXOS" = fs "80001ff" null null;
- "X11" = fs "80001ff" null null;
- "alsa" = fs "80001ff" null null;
- "bash_logout" = fs "80001ff" null null;
- "bashrc" = fs "80001ff" null null;
- "binfmt.d" = fs "80001ff" null null;
- "dbus-1" = fs "80001ff" null null;
- "default" = fs "80001ff" null null;
- "dhcpcd.exit-hook" = fs "80001ff" null null;
- "environment.d" = fs "80001ff" null null;
- "fonts" = fs "80001ff" null null;
- "fstab" = fs "80001ff" null null;
- "hsurc" = fs "80001ff" null null;
- "fuse.conf" = fs "80001ff" null null;
- "gai.conf" = fs "80001ff" null null;
- "group" = fs "180" null "hakurei:x:65534:\n";
- "host.conf" = fs "80001ff" null null;
- "hostname" = fs "80001ff" null null;
- "hosts" = fs "80001ff" null null;
- "inputrc" = fs "80001ff" null null;
- "issue" = fs "80001ff" null null;
- "kbd" = fs "80001ff" null null;
- "locale.conf" = fs "80001ff" null null;
- "login.defs" = fs "80001ff" null null;
- "lsb-release" = fs "80001ff" null null;
- "lvm" = fs "80001ff" null null;
- "machine-id" = fs "80001ff" null null;
- "man_db.conf" = fs "80001ff" null null;
- "modprobe.d" = fs "80001ff" null null;
- "modules-load.d" = fs "80001ff" null null;
- "mtab" = fs "80001ff" null null;
- "nanorc" = fs "80001ff" null null;
- "netgroup" = fs "80001ff" null null;
- "nix" = fs "80001ff" null null;
- "nixos" = fs "80001ff" null null;
- "nscd.conf" = fs "80001ff" null null;
- "nsswitch.conf" = fs "80001ff" null null;
- "os-release" = fs "80001ff" null null;
- "pam" = fs "80001ff" null null;
- "pam.d" = fs "80001ff" null null;
- "passwd" = fs "180" null "u0_a4:x:65534:65534:Hakurei:/var/lib/hakurei/u0/a4:/run/current-system/sw/bin/bash\n";
- "pipewire" = fs "80001ff" null null;
- "pki" = fs "80001ff" null null;
- "polkit-1" = fs "80001ff" null null;
- "profile" = fs "80001ff" null null;
- "protocols" = fs "80001ff" null null;
- "resolv.conf" = fs "80001ff" null null;
- "resolvconf.conf" = fs "80001ff" null null;
- "rpc" = fs "80001ff" null null;
- "services" = fs "80001ff" null null;
- "set-environment" = fs "80001ff" null null;
- "shadow" = fs "80001ff" null null;
- "shells" = fs "80001ff" null null;
- "speech-dispatcher" = fs "80001ff" null null;
- "ssh" = fs "80001ff" null null;
- "ssl" = fs "80001ff" null null;
- "static" = fs "80001ff" null null;
- "subgid" = fs "80001ff" null null;
- "subuid" = fs "80001ff" null null;
- "sudoers" = fs "80001ff" null null;
- "sway" = fs "80001ff" null null;
- "sysctl.d" = fs "80001ff" null null;
- "systemd" = fs "80001ff" null null;
- "terminfo" = fs "80001ff" null null;
- "tmpfiles.d" = fs "80001ff" null null;
- "udev" = fs "80001ff" null null;
- "vconsole.conf" = fs "80001ff" null null;
- "xdg" = fs "80001ff" null null;
- "zoneinfo" = fs "80001ff" null null;
- } null;
- nix = fs "800001c0" { store = fs "801001fd" null null; } null;
- proc = fs "8000016d" null null;
- run = fs "800001ed" {
- current-system = fs "80001ff" null null;
- opengl-driver = fs "80001ff" null null;
- user = fs "800001ed" {
- "65534" = fs "800001c0" {
- bus = fs "10001fd" null null;
- pulse = fs "800001c0" { native = fs "10001ff" null null; } null;
- wayland-0 = fs "1000038" null null;
- } null;
- } null;
- } null;
- sys = fs "800001c0" {
- block = fs "800001ed" (
- {
- ${extraPaths.${system}.fd} = fs "80001ff" null null;
- loop0 = fs "80001ff" null null;
- loop1 = fs "80001ff" null null;
- loop2 = fs "80001ff" null null;
- loop3 = fs "80001ff" null null;
- loop4 = fs "80001ff" null null;
- loop5 = fs "80001ff" null null;
- loop6 = fs "80001ff" null null;
- loop7 = fs "80001ff" null null;
- vda = fs "80001ff" null null;
- }
- // extraPaths.${system}.sr
- ) null;
- bus = fs "800001ed" null null;
- class = fs "800001ed" null null;
- dev = fs "800001ed" {
- block = fs "800001ed" null null;
- char = fs "800001ed" null null;
- } null;
- devices = fs "800001ed" null null;
- } null;
- tmp = fs "800001f8" {
- ".X11-unix" = fs "801001ff" { X0 = fs "10001fd" null null; } null;
- } null;
- usr = fs "800001c0" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null;
- var = fs "800001c0" {
- tmp = fs "801001ff" null null;
- lib = fs "800001c0" {
- hakurei = fs "800001c0" {
- u0 = fs "800001c0" {
- a4 = fs "800001c0" {
- ".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
- ".config" = fs "800001ed" {
- "environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null;
- systemd = fs "800001ed" {
- user = fs "800001ed" { "tray.target" = fs "80001ff" null null; } null;
- } null;
- } null;
- ".local" = fs "800001ed" {
- state = fs "800001ed" {
- ".keep" = fs "80001ff" null "";
- home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
- nix = fs "800001ed" {
- profiles = fs "800001ed" {
- profile = fs "80001ff" null null;
- profile-1-link = fs "80001ff" null null;
- } null;
- } null;
- } null;
- } null;
- ".nix-defexpr" = fs "800001ed" {
- channels = fs "80001ff" null null;
- channels_root = fs "80001ff" null null;
- } null;
- ".nix-profile" = fs "80001ff" null null;
- } null;
- } null;
- } null;
- } null;
- cache = fs "800001ed" { private = fs "800001c0" null null; } null;
- } null;
- } null;
-
- mount = [
- (ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10004,gid=10004")
- (ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
- (ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=10004,gid=10004")
- (ent "/" "/dev" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/" "/dev/pts" "rw,nosuid,noexec,relatime" "devpts" "devpts" "rw,gid=3,mode=620,ptmxmode=666")
- (ent "/" ignore ignore ignore ignore ignore) # not deterministic
- (ent "/" ignore ignore ignore ignore ignore)
- (ent "/" ignore ignore ignore ignore ignore)
- (ent "/" "/dev/shm" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=10004,gid=10004")
- (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=16384k,mode=755,uid=10004,gid=10004")
- (ent "/tmp/hakurei.0/tmpdir/4" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10004,gid=10004")
- (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10004,gid=10004")
- (ent ignore "/run/user/65534/wayland-0" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/tmp/.X11-unix" "/tmp/.X11-unix" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/run/user/65534/bus" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/bin" "/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/usr/bin" "/usr/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/nix/store" "ro,nosuid,nodev,relatime" "overlay" "overlay" "rw,lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/upper,workdir=/sysroot/nix/.rw-store/work,uuid=on")
- (ent "/block" "/sys/block" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/bus" "/sys/bus" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/class" "/sys/class" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/dev" "/sys/dev" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/devices" "/sys/devices" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr")
- (ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,userxattr")
- (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/var/lib/hakurei/u0/a4" "/var/lib/hakurei/u0/a4" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- ];
-
- seccomp = true;
-
- try_socket = "/tmp/.X11-unix/X0";
- socket_abstract = false;
- socket_pathname = true;
- };
-}
diff --git a/test/sandbox/case/mapuid.nix b/test/sandbox/case/mapuid.nix
deleted file mode 100644
index 1b6ef0e7..00000000
--- a/test/sandbox/case/mapuid.nix
+++ /dev/null
@@ -1,282 +0,0 @@
-{
- fs,
- ent,
- ignore,
- system,
-}:
-let
- extraPaths = {
- x86_64-linux = {
- fd = "fd0";
- "/dev/dri" = {
- by-path = fs "800001ed" {
- "pci-0000:00:09.0-card" = fs "80001ff" null null;
- "pci-0000:00:09.0-render" = fs "80001ff" null null;
- } null;
- card0 = fs "42001b0" null null;
- renderD128 = fs "42001b6" null null;
- };
- sr = {
- sr0 = fs "80001ff" null null;
- };
- };
- aarch64-linux = {
- fd = "mtdblock0";
- "/dev/dri" = null;
- sr = { };
- };
- };
-in
-{
- name = "mapuid";
- tty = false;
- device = false;
- mapRealUid = true;
- useCommonPaths = true;
- userns = false;
- x11 = false;
- hostAbstract = false;
- shareRuntime = true;
- shareTmpdir = true;
-
- # 0, PresetStrict
- expectedFilter = {
- x86_64-linux = "e880298df2bd6751d0040fc21bc0ed4c00f95dc0d7ba506c244d8b8cf6866dba8ef4a33296f287b66cccc1d78e97026597f84cc7dec1573e148960fbd35cd735";
- aarch64-linux = "79318538a3dc851314b6bd96f10d5861acb2aa7e13cb8de0619d0f6a76709d67f01ef3fd67e195862b02f9711e5b769bc4d1eb4fc0dfc41a723c89c968a93297";
- };
-
- want = {
- env = [
- "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"
- "HOME=/var/lib/hakurei/u0/a3"
- "SHELL=/run/current-system/sw/bin/bash"
- "TERM=linux"
- "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 = fs "dead" {
- ".hakurei" = fs "800001ed" {
- ".ro-store" = fs "801001fd" null null;
- store = fs "800001ff" null null;
- } null;
- bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
- dev = fs "800001ed" {
- core = fs "80001ff" null null;
- dri = fs "800001ed" extraPaths.${system}."/dev/dri" null;
- fd = fs "80001ff" null null;
- full = fs "42001b6" null null;
- mqueue = fs "801001ff" { } null;
- null = fs "42001b6" null "";
- ptmx = fs "80001ff" null null;
- pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null;
- random = fs "42001b6" null null;
- shm = fs "801001ff" { } null;
- stderr = fs "80001ff" null null;
- stdin = fs "80001ff" null null;
- stdout = fs "80001ff" null null;
- tty = fs "42001b6" null null;
- urandom = fs "42001b6" null null;
- zero = fs "42001b6" null null;
- } null;
- etc = fs "800001ed" {
- ".clean" = fs "80001ff" null null;
- ".host" = fs "800001c0" null null;
- ".updated" = fs "80001ff" null null;
- "NIXOS" = fs "80001ff" null null;
- "X11" = fs "80001ff" null null;
- "alsa" = fs "80001ff" null null;
- "bash_logout" = fs "80001ff" null null;
- "bashrc" = fs "80001ff" null null;
- "binfmt.d" = fs "80001ff" null null;
- "dbus-1" = fs "80001ff" null null;
- "default" = fs "80001ff" null null;
- "dhcpcd.exit-hook" = fs "80001ff" null null;
- "environment.d" = fs "80001ff" null null;
- "fonts" = fs "80001ff" null null;
- "fstab" = fs "80001ff" null null;
- "hsurc" = fs "80001ff" null null;
- "fuse.conf" = fs "80001ff" null null;
- "gai.conf" = fs "80001ff" null null;
- "group" = fs "180" null "hakurei:x:100:\n";
- "host.conf" = fs "80001ff" null null;
- "hostname" = fs "80001ff" null null;
- "hosts" = fs "80001ff" null null;
- "inputrc" = fs "80001ff" null null;
- "issue" = fs "80001ff" null null;
- "kbd" = fs "80001ff" null null;
- "locale.conf" = fs "80001ff" null null;
- "login.defs" = fs "80001ff" null null;
- "lsb-release" = fs "80001ff" null null;
- "lvm" = fs "80001ff" null null;
- "machine-id" = fs "80001ff" null null;
- "man_db.conf" = fs "80001ff" null null;
- "modprobe.d" = fs "80001ff" null null;
- "modules-load.d" = fs "80001ff" null null;
- "mtab" = fs "80001ff" null null;
- "nanorc" = fs "80001ff" null null;
- "netgroup" = fs "80001ff" null null;
- "nix" = fs "80001ff" null null;
- "nixos" = fs "80001ff" null null;
- "nscd.conf" = fs "80001ff" null null;
- "nsswitch.conf" = fs "80001ff" null null;
- "os-release" = fs "80001ff" null null;
- "pam" = fs "80001ff" null null;
- "pam.d" = fs "80001ff" null null;
- "passwd" = fs "180" null "u0_a3:x:1000:100:Hakurei:/var/lib/hakurei/u0/a3:/run/current-system/sw/bin/bash\n";
- "pipewire" = fs "80001ff" null null;
- "pki" = fs "80001ff" null null;
- "polkit-1" = fs "80001ff" null null;
- "profile" = fs "80001ff" null null;
- "protocols" = fs "80001ff" null null;
- "resolv.conf" = fs "80001ff" null null;
- "resolvconf.conf" = fs "80001ff" null null;
- "rpc" = fs "80001ff" null null;
- "services" = fs "80001ff" null null;
- "set-environment" = fs "80001ff" null null;
- "shadow" = fs "80001ff" null null;
- "shells" = fs "80001ff" null null;
- "speech-dispatcher" = fs "80001ff" null null;
- "ssh" = fs "80001ff" null null;
- "ssl" = fs "80001ff" null null;
- "static" = fs "80001ff" null null;
- "subgid" = fs "80001ff" null null;
- "subuid" = fs "80001ff" null null;
- "sudoers" = fs "80001ff" null null;
- "sway" = fs "80001ff" null null;
- "sysctl.d" = fs "80001ff" null null;
- "systemd" = fs "80001ff" null null;
- "terminfo" = fs "80001ff" null null;
- "tmpfiles.d" = fs "80001ff" null null;
- "udev" = fs "80001ff" null null;
- "vconsole.conf" = fs "80001ff" null null;
- "xdg" = fs "80001ff" null null;
- "zoneinfo" = fs "80001ff" null null;
- } null;
- nix = fs "800001c0" { store = fs "801001fd" null null; } null;
- proc = fs "8000016d" null null;
- run = fs "800001ed" {
- current-system = fs "80001ff" null null;
- opengl-driver = fs "80001ff" null null;
- user = fs "800001ed" {
- "1000" = fs "800001f8" {
- bus = fs "10001fd" null null;
- pulse = fs "800001c0" { native = fs "10001ff" null null; } null;
- wayland-0 = fs "1000038" null null;
- } null;
- } null;
- } null;
- sys = fs "800001c0" {
- block = fs "800001ed" (
- {
- ${extraPaths.${system}.fd} = fs "80001ff" null null;
- loop0 = fs "80001ff" null null;
- loop1 = fs "80001ff" null null;
- loop2 = fs "80001ff" null null;
- loop3 = fs "80001ff" null null;
- loop4 = fs "80001ff" null null;
- loop5 = fs "80001ff" null null;
- loop6 = fs "80001ff" null null;
- loop7 = fs "80001ff" null null;
- vda = fs "80001ff" null null;
- }
- // extraPaths.${system}.sr
- ) null;
- bus = fs "800001ed" null null;
- class = fs "800001ed" null null;
- dev = fs "800001ed" {
- block = fs "800001ed" null null;
- char = fs "800001ed" null null;
- } null;
- devices = fs "800001ed" null null;
- } null;
- tmp = fs "800001f8" { } null;
- usr = fs "800001c0" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null;
- var = fs "800001c0" {
- tmp = fs "801001ff" null null;
- lib = fs "800001c0" {
- hakurei = fs "800001c0" {
- u0 = fs "800001c0" {
- a3 = fs "800001c0" {
- ".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
- ".config" = fs "800001ed" {
- "environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null;
- systemd = fs "800001ed" {
- user = fs "800001ed" { "tray.target" = fs "80001ff" null null; } null;
- } null;
- } null;
- ".local" = fs "800001ed" {
- state = fs "800001ed" {
- ".keep" = fs "80001ff" null "";
- home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
- nix = fs "800001ed" {
- profiles = fs "800001ed" {
- profile = fs "80001ff" null null;
- profile-1-link = fs "80001ff" null null;
- } null;
- } null;
- } null;
- } null;
- ".nix-defexpr" = fs "800001ed" {
- channels = fs "80001ff" null null;
- channels_root = fs "80001ff" null null;
- } null;
- ".nix-profile" = fs "80001ff" null null;
- } null;
- } null;
- } null;
- } null;
- cache = fs "800001ed" { private = fs "800001c0" null null; } null;
- } null;
- } null;
-
- mount = [
- (ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10003,gid=10003")
- (ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
- (ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=10003,gid=10003")
- (ent "/" "/dev" "ro,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=10003,gid=10003")
- (ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/random" "/dev/random" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/urandom" "/dev/urandom" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/tty" "/dev/tty" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/" "/dev/pts" "rw,nosuid,noexec,relatime" "devpts" "devpts" "rw,mode=620,ptmxmode=666")
- (ent "/" "/dev/mqueue" "rw,nosuid,nodev,noexec,relatime" "mqueue" "mqueue" "rw")
- (ent "/" "/dev/shm" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=10003,gid=10003")
- (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=16384k,mode=755,uid=10003,gid=10003")
- (ent "/tmp/hakurei.0/runtime/3" "/run/user/1000" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/tmp/hakurei.0/tmpdir/3" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10003,gid=10003")
- (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10003,gid=10003")
- (ent ignore "/run/user/1000/wayland-0" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/run/user/1000/bus" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/bin" "/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/usr/bin" "/usr/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/nix/store" "ro,nosuid,nodev,relatime" "overlay" "overlay" "rw,lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/upper,workdir=/sysroot/nix/.rw-store/work,uuid=on")
- (ent "/block" "/sys/block" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/bus" "/sys/bus" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/class" "/sys/class" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/dev" "/sys/dev" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/devices" "/sys/devices" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr")
- (ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,userxattr")
- (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/var/lib/hakurei/u0/a3" "/var/lib/hakurei/u0/a3" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/run/user/1000/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- ];
-
- seccomp = true;
-
- try_socket = "/tmp/.X11-unix/X0";
- socket_abstract = false;
- socket_pathname = false;
- };
-}
diff --git a/test/sandbox/case/pd.nix b/test/sandbox/case/pd.nix
deleted file mode 100644
index 25f42979..00000000
--- a/test/sandbox/case/pd.nix
+++ /dev/null
@@ -1,206 +0,0 @@
-{
- fs,
- ent,
- ignore,
- ...
-}:
-{
- # 0, PresetExt | PresetDenyDevel
- expectedFilter = {
- x86_64-linux = "c698b081ff957afe17a6d94374537d37f2a63f6f9dd75da7546542407a9e32476ebda3312ba7785d7f618542bcfaf27ca27dcc2dddba852069d28bcfe8cad39a";
- aarch64-linux = "433ce9b911282d6dcc8029319fb79b816b60d5a795ec8fc94344dd027614d68f023166a91bb881faaeeedd26e3d89474e141e5a69a97e93b8984ca8f14999980";
- };
-
- want = {
- env = [
- "HOME=/var/lib/hakurei/u0/a0"
- "SHELL=/run/current-system/sw/bin/bash"
- "TERM=linux"
- "USER=u0_a0"
- "XDG_RUNTIME_DIR=/run/user/65534"
- "XDG_SESSION_CLASS=user"
- "XDG_SESSION_TYPE=tty"
- ];
-
- fs = fs "dead" {
- ".hakurei" = fs "800001ed" { } null;
- bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
- dev = fs "800001ed" {
- console = fs "4200190" null null;
- core = fs "80001ff" null null;
- fd = fs "80001ff" null null;
- full = fs "42001b6" null null;
- kvm = fs "42001b6" null null;
- mqueue = fs "801001ff" { } null;
- null = fs "42001b6" null "";
- ptmx = fs "80001ff" null null;
- pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null;
- random = fs "42001b6" null null;
- shm = fs "801001ff" { } null;
- stderr = fs "80001ff" null null;
- stdin = fs "80001ff" null null;
- stdout = fs "80001ff" null null;
- tty = fs "42001b6" null null;
- urandom = fs "42001b6" null null;
- zero = fs "42001b6" null null;
- } null;
- etc = fs "800001ed" {
- ".clean" = fs "80001ff" null null;
- ".host" = fs "800001c0" null null;
- ".updated" = fs "80001ff" null null;
- "NIXOS" = fs "80001ff" null null;
- "X11" = fs "80001ff" null null;
- "alsa" = fs "80001ff" null null;
- "bash_logout" = fs "80001ff" null null;
- "bashrc" = fs "80001ff" null null;
- "binfmt.d" = fs "80001ff" null null;
- "dbus-1" = fs "80001ff" null null;
- "default" = fs "80001ff" null null;
- "dhcpcd.exit-hook" = fs "80001ff" null null;
- "environment.d" = fs "80001ff" null null;
- "fonts" = fs "80001ff" null null;
- "fstab" = fs "80001ff" null null;
- "hsurc" = fs "80001ff" null null;
- "fuse.conf" = fs "80001ff" null null;
- "gai.conf" = fs "80001ff" null null;
- "group" = fs "180" null "hakurei:x:65534:\n";
- "host.conf" = fs "80001ff" null null;
- "hostname" = fs "80001ff" null null;
- "hosts" = fs "80001ff" null null;
- "inputrc" = fs "80001ff" null null;
- "issue" = fs "80001ff" null null;
- "kbd" = fs "80001ff" null null;
- "locale.conf" = fs "80001ff" null null;
- "login.defs" = fs "80001ff" null null;
- "lsb-release" = fs "80001ff" null null;
- "lvm" = fs "80001ff" null null;
- "machine-id" = fs "80001ff" null null;
- "man_db.conf" = fs "80001ff" null null;
- "modprobe.d" = fs "80001ff" null null;
- "modules-load.d" = fs "80001ff" null null;
- "mtab" = fs "80001ff" null null;
- "nanorc" = fs "80001ff" null null;
- "netgroup" = fs "80001ff" null null;
- "nix" = fs "80001ff" null null;
- "nixos" = fs "80001ff" null null;
- "nscd.conf" = fs "80001ff" null null;
- "nsswitch.conf" = fs "80001ff" null null;
- "os-release" = fs "80001ff" null null;
- "pam" = fs "80001ff" null null;
- "pam.d" = fs "80001ff" null null;
- "passwd" = fs "180" null "u0_a0:x:65534:65534:Hakurei:/var/lib/hakurei/u0/a0:/run/current-system/sw/bin/bash\n";
- "pipewire" = fs "80001ff" null null;
- "pki" = fs "80001ff" null null;
- "polkit-1" = fs "80001ff" null null;
- "profile" = fs "80001ff" null null;
- "protocols" = fs "80001ff" null null;
- "resolv.conf" = fs "80001ff" null null;
- "resolvconf.conf" = fs "80001ff" null null;
- "rpc" = fs "80001ff" null null;
- "services" = fs "80001ff" null null;
- "set-environment" = fs "80001ff" null null;
- "shadow" = fs "80001ff" null null;
- "shells" = fs "80001ff" null null;
- "speech-dispatcher" = fs "80001ff" null null;
- "ssh" = fs "80001ff" null null;
- "ssl" = fs "80001ff" null null;
- "static" = fs "80001ff" null null;
- "subgid" = fs "80001ff" null null;
- "subuid" = fs "80001ff" null null;
- "sudoers" = fs "80001ff" null null;
- "sway" = fs "80001ff" null null;
- "sysctl.d" = fs "80001ff" null null;
- "systemd" = fs "80001ff" null null;
- "terminfo" = fs "80001ff" null null;
- "tmpfiles.d" = fs "80001ff" null null;
- "udev" = fs "80001ff" null null;
- "vconsole.conf" = fs "80001ff" null null;
- "xdg" = fs "80001ff" null null;
- "zoneinfo" = fs "80001ff" null null;
- } null;
- home = fs "800001ed" { alice = fs "800001c0" null null; } null;
- lib64 = fs "800001ed" { "ld-linux-x86-64.so.2" = fs "80001ff" null null; } null;
- "lost+found" = fs "800001c0" null null;
- nix = fs "800001ed" {
- ".ro-store" = fs "801001fd" null null;
- ".rw-store" = fs "800001ed" null null;
- store = fs "801001fd" null null;
- var = fs "800001ed" {
- log = fs "800001ed" null null;
- nix = fs "800001ed" null null;
- } null;
- } null;
- proc = fs "8000016d" null null;
- root = fs "800001c0" null null;
- run = fs "800001ed" null null;
- srv = fs "800001ed" { } null;
- sys = fs "8000016d" null null;
- tmp = fs "800001f8" { } null;
- usr = fs "800001ed" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null;
- var = fs "800001ed" null null;
- } null;
-
- mount = [
- (ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10000,gid=10000")
- (ent "/bin" "/bin" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/home" "/home" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/lib64" "/lib64" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/lost+found" "/lost+found" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/nix" "/nix" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- # systemd nondeterminism: ro-store rw-store
- (ent "/" ignore "rw,nosuid,nodev,relatime" ignore ignore ignore)
- (ent "/" ignore "rw,nosuid,nodev,relatime" ignore ignore ignore)
- (ent "/" "/nix/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/upper,workdir=/sysroot/nix/.rw-store/work,uuid=on")
- (ent "/" "/nix/store" "ro,nosuid,nodev,relatime" "overlay" "overlay" "rw,lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/upper,workdir=/sysroot/nix/.rw-store/work,uuid=on")
- (ent "/root" "/root" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/run" "rw,nosuid,nodev" "tmpfs" "tmpfs" ignore)
- (ent "/" "/run/keys" "rw,nosuid,nodev,relatime" "ramfs" "ramfs" "rw,mode=750")
- (ent "/" "/run/credentials/systemd-journald.service" "rw,nosuid,nodev,noexec,relatime,nosymfollow" "tmpfs" "none" "ro,size=1024k,nr_inodes=1024,mode=700,noswap")
- (ent "/" "/run/wrappers" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" ignore)
- (ent "/" "/run/credentials/getty@tty1.service" "rw,nosuid,nodev,noexec,relatime,nosymfollow" "tmpfs" "none" "ro,size=1024k,nr_inodes=1024,mode=700,noswap")
- (ent "/" "/run/user/1000" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" ignore)
- (ent "/srv" "/srv" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/sys" "rw,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/" "/sys/kernel/security" "rw,nosuid,nodev,noexec,relatime" "securityfs" "securityfs" "rw")
- (ent "/../../.." "/sys/fs/cgroup" "rw,nosuid,nodev,noexec,relatime" "cgroup2" "cgroup2" "rw,nsdelegate,memory_recursiveprot,memory_hugetlb_accounting")
- (ent "/" "/sys/fs/pstore" "rw,nosuid,nodev,noexec,relatime" "pstore" "none" "rw")
- (ent "/" "/sys/fs/bpf" "rw,nosuid,nodev,noexec,relatime" "bpf" "bpf" "rw,mode=700")
- # systemd nondeterminism: tracefs debugfs configfs fusectl
- (ent "/" ignore "rw,nosuid,nodev,noexec,relatime" ignore ignore "rw")
- (ent "/" ignore "rw,nosuid,nodev,noexec,relatime" ignore ignore "rw")
- (ent "/" ignore "rw,nosuid,nodev,noexec,relatime" ignore ignore "rw")
- (ent "/" ignore "rw,nosuid,nodev,noexec,relatime" ignore ignore "rw")
- (ent "/usr" "/usr" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/var" "/var" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
- (ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=10000,gid=10000")
- (ent "/" "/dev" "ro,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=10000,gid=10000")
- (ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/random" "/dev/random" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/urandom" "/dev/urandom" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/tty" "/dev/tty" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/" "/dev/pts" "rw,nosuid,noexec,relatime" "devpts" "devpts" "rw,mode=620,ptmxmode=666")
- (ent ignore "/dev/console" "rw,nosuid,noexec,relatime" "devpts" "devpts" "rw,gid=3,mode=620,ptmxmode=666")
- (ent "/" "/dev/mqueue" "rw,nosuid,nodev,noexec,relatime" "mqueue" "mqueue" "rw")
- (ent "/" "/dev/shm" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=10000,gid=10000")
- (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=16384k,mode=755,uid=10000,gid=10000")
- (ent "/tmp/hakurei.0/runtime/0" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/tmp/hakurei.0/tmpdir/0" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10000,gid=10000")
- (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10000,gid=10000")
- (ent "/kvm" "/dev/kvm" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/run/user/1000" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=8k,mode=755,uid=10000,gid=10000")
- (ent "/" "/run/nscd" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=8k,mode=755,uid=10000,gid=10000")
- (ent "/" "/run/dbus" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=8k,mode=755,uid=10000,gid=10000")
- ];
-
- seccomp = true;
-
- try_socket = "/tmp/.X11-unix/X0";
- socket_abstract = true;
- socket_pathname = false;
- };
-}
diff --git a/test/sandbox/case/pdlike.nix b/test/sandbox/case/pdlike.nix
deleted file mode 100644
index 7f0716fb..00000000
--- a/test/sandbox/case/pdlike.nix
+++ /dev/null
@@ -1,277 +0,0 @@
-{
- fs,
- ent,
- ignore,
- system,
-}:
-let
- extraPaths = {
- x86_64-linux = {
- fd = "fd0";
- "/dev/dri" = {
- by-path = fs "800001ed" {
- "pci-0000:00:09.0-card" = fs "80001ff" null null;
- "pci-0000:00:09.0-render" = fs "80001ff" null null;
- } null;
- card0 = fs "42001b0" null null;
- renderD128 = fs "42001b6" null null;
- };
- sr = {
- sr0 = fs "80001ff" null null;
- };
- };
- aarch64-linux = {
- fd = "mtdblock0";
- "/dev/dri" = null;
- sr = { };
- };
- };
-in
-{
- name = "pdlike";
- tty = true;
- device = false;
- mapRealUid = false;
- useCommonPaths = false;
- userns = true;
- x11 = false;
- hostAbstract = false;
- shareRuntime = true;
- shareTmpdir = true;
-
- # 0, PresetExt | PresetDenyDevel
- expectedFilter = {
- x86_64-linux = "c698b081ff957afe17a6d94374537d37f2a63f6f9dd75da7546542407a9e32476ebda3312ba7785d7f618542bcfaf27ca27dcc2dddba852069d28bcfe8cad39a";
- aarch64-linux = "433ce9b911282d6dcc8029319fb79b816b60d5a795ec8fc94344dd027614d68f023166a91bb881faaeeedd26e3d89474e141e5a69a97e93b8984ca8f14999980";
- };
-
- want = {
- env = [
- "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus"
- "HOME=/var/lib/hakurei/u0/a5"
- "SHELL=/run/current-system/sw/bin/bash"
- "TERM=linux"
- "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 = fs "dead" {
- ".hakurei" = fs "800001ed" { } null;
- bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
- dev = fs "800001ed" {
- console = fs "4200190" null null;
- core = fs "80001ff" null null;
- dri = fs "800001ed" extraPaths.${system}."/dev/dri" null;
- fd = fs "80001ff" null null;
- full = fs "42001b6" null null;
- mqueue = fs "801001ff" { } null;
- null = fs "42001b6" null "";
- ptmx = fs "80001ff" null null;
- pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null;
- random = fs "42001b6" null null;
- shm = fs "801001ff" { } null;
- stderr = fs "80001ff" null null;
- stdin = fs "80001ff" null null;
- stdout = fs "80001ff" null null;
- tty = fs "42001b6" null null;
- urandom = fs "42001b6" null null;
- zero = fs "42001b6" null null;
- } null;
- etc = fs "800001ed" {
- ".clean" = fs "80001ff" null null;
- ".host" = fs "800001c0" null null;
- ".updated" = fs "80001ff" null null;
- "NIXOS" = fs "80001ff" null null;
- "X11" = fs "80001ff" null null;
- "alsa" = fs "80001ff" null null;
- "bash_logout" = fs "80001ff" null null;
- "bashrc" = fs "80001ff" null null;
- "binfmt.d" = fs "80001ff" null null;
- "dbus-1" = fs "80001ff" null null;
- "default" = fs "80001ff" null null;
- "dhcpcd.exit-hook" = fs "80001ff" null null;
- "environment.d" = fs "80001ff" null null;
- "fonts" = fs "80001ff" null null;
- "fstab" = fs "80001ff" null null;
- "hsurc" = fs "80001ff" null null;
- "fuse.conf" = fs "80001ff" null null;
- "gai.conf" = fs "80001ff" null null;
- "group" = fs "180" null "hakurei:x:65534:\n";
- "host.conf" = fs "80001ff" null null;
- "hostname" = fs "80001ff" null null;
- "hosts" = fs "80001ff" null null;
- "inputrc" = fs "80001ff" null null;
- "issue" = fs "80001ff" null null;
- "kbd" = fs "80001ff" null null;
- "locale.conf" = fs "80001ff" null null;
- "login.defs" = fs "80001ff" null null;
- "lsb-release" = fs "80001ff" null null;
- "lvm" = fs "80001ff" null null;
- "machine-id" = fs "80001ff" null null;
- "man_db.conf" = fs "80001ff" null null;
- "modprobe.d" = fs "80001ff" null null;
- "modules-load.d" = fs "80001ff" null null;
- "mtab" = fs "80001ff" null null;
- "nanorc" = fs "80001ff" null null;
- "netgroup" = fs "80001ff" null null;
- "nix" = fs "80001ff" null null;
- "nixos" = fs "80001ff" null null;
- "nscd.conf" = fs "80001ff" null null;
- "nsswitch.conf" = fs "80001ff" null null;
- "os-release" = fs "80001ff" null null;
- "pam" = fs "80001ff" null null;
- "pam.d" = fs "80001ff" null null;
- "passwd" = fs "180" null "u0_a5:x:65534:65534:Hakurei:/var/lib/hakurei/u0/a5:/run/current-system/sw/bin/bash\n";
- "pipewire" = fs "80001ff" null null;
- "pki" = fs "80001ff" null null;
- "polkit-1" = fs "80001ff" null null;
- "profile" = fs "80001ff" null null;
- "protocols" = fs "80001ff" null null;
- "resolv.conf" = fs "80001ff" null null;
- "resolvconf.conf" = fs "80001ff" null null;
- "rpc" = fs "80001ff" null null;
- "services" = fs "80001ff" null null;
- "set-environment" = fs "80001ff" null null;
- "shadow" = fs "80001ff" null null;
- "shells" = fs "80001ff" null null;
- "speech-dispatcher" = fs "80001ff" null null;
- "ssh" = fs "80001ff" null null;
- "ssl" = fs "80001ff" null null;
- "static" = fs "80001ff" null null;
- "subgid" = fs "80001ff" null null;
- "subuid" = fs "80001ff" null null;
- "sudoers" = fs "80001ff" null null;
- "sway" = fs "80001ff" null null;
- "sysctl.d" = fs "80001ff" null null;
- "systemd" = fs "80001ff" null null;
- "terminfo" = fs "80001ff" null null;
- "tmpfiles.d" = fs "80001ff" null null;
- "udev" = fs "80001ff" null null;
- "vconsole.conf" = fs "80001ff" null null;
- "xdg" = fs "80001ff" null null;
- "zoneinfo" = fs "80001ff" null null;
- } null;
- nix = fs "800001c0" { store = fs "801001fd" null null; } null;
- proc = fs "8000016d" null null;
- run = fs "800001ed" {
- current-system = fs "80001ff" null null;
- opengl-driver = fs "80001ff" null null;
- user = fs "800001ed" {
- "65534" = fs "800001f8" {
- bus = fs "10001fd" null null;
- pulse = fs "800001c0" { native = fs "10001ff" null null; } null;
- wayland-0 = fs "1000038" null null;
- } null;
- } null;
- } null;
- sys = fs "800001c0" {
- block = fs "800001ed" (
- {
- ${extraPaths.${system}.fd} = fs "80001ff" null null;
- loop0 = fs "80001ff" null null;
- loop1 = fs "80001ff" null null;
- loop2 = fs "80001ff" null null;
- loop3 = fs "80001ff" null null;
- loop4 = fs "80001ff" null null;
- loop5 = fs "80001ff" null null;
- loop6 = fs "80001ff" null null;
- loop7 = fs "80001ff" null null;
- vda = fs "80001ff" null null;
- }
- // extraPaths.${system}.sr
- ) null;
- bus = fs "800001ed" null null;
- class = fs "800001ed" null null;
- dev = fs "800001ed" {
- block = fs "800001ed" null null;
- char = fs "800001ed" null null;
- } null;
- devices = fs "800001ed" null null;
- } null;
- tmp = fs "800001f8" { } null;
- usr = fs "800001c0" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null;
- var = fs "800001c0" {
- tmp = fs "801001ff" null null;
- lib = fs "800001c0" {
- hakurei = fs "800001c0" {
- u0 = fs "800001c0" {
- a5 = fs "800001c0" {
- ".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
- ".config" = fs "800001ed" {
- "environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null;
- systemd = fs "800001ed" {
- user = fs "800001ed" { "tray.target" = fs "80001ff" null null; } null;
- } null;
- } null;
- ".local" = fs "800001ed" {
- state = fs "800001ed" {
- ".keep" = fs "80001ff" null "";
- home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
- nix = fs "800001ed" {
- profiles = fs "800001ed" {
- profile = fs "80001ff" null null;
- profile-1-link = fs "80001ff" null null;
- } null;
- } null;
- } null;
- } null;
- ".nix-defexpr" = fs "800001ed" {
- channels = fs "80001ff" null null;
- channels_root = fs "80001ff" null null;
- } null;
- ".nix-profile" = fs "80001ff" null null;
- } null;
- } null;
- } null;
- } null;
- } null;
- } null;
-
- mount = [
- (ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10005,gid=10005")
- (ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
- (ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=10005,gid=10005")
- (ent "/" "/dev" "ro,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=10005,gid=10005")
- (ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/random" "/dev/random" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/urandom" "/dev/urandom" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/tty" "/dev/tty" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/" "/dev/pts" "rw,nosuid,noexec,relatime" "devpts" "devpts" "rw,mode=620,ptmxmode=666")
- (ent ignore "/dev/console" "rw,nosuid,noexec,relatime" "devpts" "devpts" "rw,gid=3,mode=620,ptmxmode=666")
- (ent "/" "/dev/mqueue" "rw,nosuid,nodev,noexec,relatime" "mqueue" "mqueue" "rw")
- (ent "/" "/dev/shm" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=10005,gid=10005")
- (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=16384k,mode=755,uid=10005,gid=10005")
- (ent "/tmp/hakurei.0/runtime/5" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/tmp/hakurei.0/tmpdir/5" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10005,gid=10005")
- (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10005,gid=10005")
- (ent ignore "/run/user/65534/wayland-0" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/run/user/65534/bus" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/bin" "/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/usr/bin" "/usr/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/nix/store" "ro,nosuid,nodev,relatime" "overlay" "overlay" "rw,lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/upper,workdir=/sysroot/nix/.rw-store/work,uuid=on")
- (ent "/block" "/sys/block" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/bus" "/sys/bus" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/class" "/sys/class" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/dev" "/sys/dev" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/devices" "/sys/devices" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/var/lib/hakurei/u0/a5" "/var/lib/hakurei/u0/a5" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- ];
-
- seccomp = true;
-
- try_socket = "/tmp/.X11-unix/X0";
- socket_abstract = false;
- socket_pathname = false;
- };
-}
diff --git a/test/sandbox/case/preset.nix b/test/sandbox/case/preset.nix
deleted file mode 100644
index 33cc3b8b..00000000
--- a/test/sandbox/case/preset.nix
+++ /dev/null
@@ -1,274 +0,0 @@
-{
- fs,
- ent,
- ignore,
- system,
-}:
-let
- extraPaths = {
- x86_64-linux = {
- fd = "fd0";
- "/dev/dri" = {
- by-path = fs "800001ed" {
- "pci-0000:00:09.0-card" = fs "80001ff" null null;
- "pci-0000:00:09.0-render" = fs "80001ff" null null;
- } null;
- card0 = fs "42001b0" null null;
- renderD128 = fs "42001b6" null null;
- };
- sr = {
- sr0 = fs "80001ff" null null;
- };
- };
- aarch64-linux = {
- fd = "mtdblock0";
- "/dev/dri" = null;
- sr = { };
- };
- };
-in
-{
- name = "preset";
- tty = false;
- device = false;
- mapRealUid = false;
- useCommonPaths = false;
- userns = false;
- x11 = false;
- hostAbstract = false;
- shareRuntime = false;
- shareTmpdir = false;
-
- # 0, PresetStrict
- expectedFilter = {
- x86_64-linux = "e880298df2bd6751d0040fc21bc0ed4c00f95dc0d7ba506c244d8b8cf6866dba8ef4a33296f287b66cccc1d78e97026597f84cc7dec1573e148960fbd35cd735";
- aarch64-linux = "79318538a3dc851314b6bd96f10d5861acb2aa7e13cb8de0619d0f6a76709d67f01ef3fd67e195862b02f9711e5b769bc4d1eb4fc0dfc41a723c89c968a93297";
- };
-
- want = {
- env = [
- "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus"
- "HOME=/var/lib/hakurei/u0/a1"
- "SHELL=/run/current-system/sw/bin/bash"
- "TERM=linux"
- "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 = fs "dead" {
- ".hakurei" = fs "800001ed" { } null;
- bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
- dev = fs "800001ed" {
- core = fs "80001ff" null null;
- dri = fs "800001ed" extraPaths.${system}."/dev/dri" null;
- fd = fs "80001ff" null null;
- full = fs "42001b6" null null;
- mqueue = fs "801001ff" { } null;
- null = fs "42001b6" null "";
- ptmx = fs "80001ff" null null;
- pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null;
- random = fs "42001b6" null null;
- shm = fs "801001ff" { } null;
- stderr = fs "80001ff" null null;
- stdin = fs "80001ff" null null;
- stdout = fs "80001ff" null null;
- tty = fs "42001b6" null null;
- urandom = fs "42001b6" null null;
- zero = fs "42001b6" null null;
- } null;
- etc = fs "800001ed" {
- ".clean" = fs "80001ff" null null;
- ".host" = fs "800001c0" null null;
- ".updated" = fs "80001ff" null null;
- "NIXOS" = fs "80001ff" null null;
- "X11" = fs "80001ff" null null;
- "alsa" = fs "80001ff" null null;
- "bash_logout" = fs "80001ff" null null;
- "bashrc" = fs "80001ff" null null;
- "binfmt.d" = fs "80001ff" null null;
- "dbus-1" = fs "80001ff" null null;
- "default" = fs "80001ff" null null;
- "dhcpcd.exit-hook" = fs "80001ff" null null;
- "environment.d" = fs "80001ff" null null;
- "fonts" = fs "80001ff" null null;
- "fstab" = fs "80001ff" null null;
- "hsurc" = fs "80001ff" null null;
- "fuse.conf" = fs "80001ff" null null;
- "gai.conf" = fs "80001ff" null null;
- "group" = fs "180" null "hakurei:x:65534:\n";
- "host.conf" = fs "80001ff" null null;
- "hostname" = fs "80001ff" null null;
- "hosts" = fs "80001ff" null null;
- "inputrc" = fs "80001ff" null null;
- "issue" = fs "80001ff" null null;
- "kbd" = fs "80001ff" null null;
- "locale.conf" = fs "80001ff" null null;
- "login.defs" = fs "80001ff" null null;
- "lsb-release" = fs "80001ff" null null;
- "lvm" = fs "80001ff" null null;
- "machine-id" = fs "80001ff" null null;
- "man_db.conf" = fs "80001ff" null null;
- "modprobe.d" = fs "80001ff" null null;
- "modules-load.d" = fs "80001ff" null null;
- "mtab" = fs "80001ff" null null;
- "nanorc" = fs "80001ff" null null;
- "netgroup" = fs "80001ff" null null;
- "nix" = fs "80001ff" null null;
- "nixos" = fs "80001ff" null null;
- "nscd.conf" = fs "80001ff" null null;
- "nsswitch.conf" = fs "80001ff" null null;
- "os-release" = fs "80001ff" null null;
- "pam" = fs "80001ff" null null;
- "pam.d" = fs "80001ff" null null;
- "passwd" = fs "180" null "u0_a1:x:65534:65534:Hakurei:/var/lib/hakurei/u0/a1:/run/current-system/sw/bin/bash\n";
- "pipewire" = fs "80001ff" null null;
- "pki" = fs "80001ff" null null;
- "polkit-1" = fs "80001ff" null null;
- "profile" = fs "80001ff" null null;
- "protocols" = fs "80001ff" null null;
- "resolv.conf" = fs "80001ff" null null;
- "resolvconf.conf" = fs "80001ff" null null;
- "rpc" = fs "80001ff" null null;
- "services" = fs "80001ff" null null;
- "set-environment" = fs "80001ff" null null;
- "shadow" = fs "80001ff" null null;
- "shells" = fs "80001ff" null null;
- "speech-dispatcher" = fs "80001ff" null null;
- "ssh" = fs "80001ff" null null;
- "ssl" = fs "80001ff" null null;
- "static" = fs "80001ff" null null;
- "subgid" = fs "80001ff" null null;
- "subuid" = fs "80001ff" null null;
- "sudoers" = fs "80001ff" null null;
- "sway" = fs "80001ff" null null;
- "sysctl.d" = fs "80001ff" null null;
- "systemd" = fs "80001ff" null null;
- "terminfo" = fs "80001ff" null null;
- "tmpfiles.d" = fs "80001ff" null null;
- "udev" = fs "80001ff" null null;
- "vconsole.conf" = fs "80001ff" null null;
- "xdg" = fs "80001ff" null null;
- "zoneinfo" = fs "80001ff" null null;
- } null;
- nix = fs "800001c0" { store = fs "801001fd" null null; } null;
- proc = fs "8000016d" null null;
- run = fs "800001ed" {
- current-system = fs "80001ff" null null;
- opengl-driver = fs "80001ff" null null;
- user = fs "800001ed" {
- "65534" = fs "800001c0" {
- bus = fs "10001fd" null null;
- pulse = fs "800001c0" { native = fs "10001ff" null null; } null;
- wayland-0 = fs "1000038" null null;
- } null;
- } null;
- } null;
- sys = fs "800001c0" {
- block = fs "800001ed" (
- {
- ${extraPaths.${system}.fd} = fs "80001ff" null null;
- loop0 = fs "80001ff" null null;
- loop1 = fs "80001ff" null null;
- loop2 = fs "80001ff" null null;
- loop3 = fs "80001ff" null null;
- loop4 = fs "80001ff" null null;
- loop5 = fs "80001ff" null null;
- loop6 = fs "80001ff" null null;
- loop7 = fs "80001ff" null null;
- vda = fs "80001ff" null null;
- }
- // extraPaths.${system}.sr
- ) null;
- bus = fs "800001ed" null null;
- class = fs "800001ed" null null;
- dev = fs "800001ed" {
- block = fs "800001ed" null null;
- char = fs "800001ed" null null;
- } null;
- devices = fs "800001ed" null null;
- } null;
- tmp = fs "801001ff" { } null;
- usr = fs "800001c0" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null;
- var = fs "800001c0" {
- tmp = fs "801001ff" null null;
- lib = fs "800001c0" {
- hakurei = fs "800001c0" {
- u0 = fs "800001c0" {
- a1 = fs "800001c0" {
- ".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
- ".config" = fs "800001ed" {
- "environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null;
- systemd = fs "800001ed" {
- user = fs "800001ed" { "tray.target" = fs "80001ff" null null; } null;
- } null;
- } null;
- ".local" = fs "800001ed" {
- state = fs "800001ed" {
- ".keep" = fs "80001ff" null "";
- home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
- nix = fs "800001ed" {
- profiles = fs "800001ed" {
- profile = fs "80001ff" null null;
- profile-1-link = fs "80001ff" null null;
- } null;
- } null;
- } null;
- } null;
- ".nix-defexpr" = fs "800001ed" {
- channels = fs "80001ff" null null;
- channels_root = fs "80001ff" null null;
- } null;
- ".nix-profile" = fs "80001ff" null null;
- } null;
- } null;
- } null;
- } null;
- } null;
- } null;
-
- mount = [
- (ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10001,gid=10001")
- (ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
- (ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=10001,gid=10001")
- (ent "/" "/dev" "ro,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=10001,gid=10001")
- (ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/random" "/dev/random" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/urandom" "/dev/urandom" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/tty" "/dev/tty" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/" "/dev/pts" "rw,nosuid,noexec,relatime" "devpts" "devpts" "rw,mode=620,ptmxmode=666")
- (ent "/" "/dev/mqueue" "rw,nosuid,nodev,noexec,relatime" "mqueue" "mqueue" "rw")
- (ent "/" "/dev/shm" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=10001,gid=10001")
- (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=16384k,mode=755,uid=10001,gid=10001")
- (ent "/" "/tmp" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=10001,gid=10001")
- (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10001,gid=10001")
- (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10001,gid=10001")
- (ent ignore "/run/user/65534/wayland-0" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/run/user/65534/bus" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/bin" "/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/usr/bin" "/usr/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/nix/store" "ro,nosuid,nodev,relatime" "overlay" "overlay" "rw,lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/upper,workdir=/sysroot/nix/.rw-store/work,uuid=on")
- (ent "/block" "/sys/block" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/bus" "/sys/bus" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/class" "/sys/class" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/dev" "/sys/dev" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/devices" "/sys/devices" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/var/lib/hakurei/u0/a1" "/var/lib/hakurei/u0/a1" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- ];
-
- seccomp = true;
-
- try_socket = "/tmp/.X11-unix/X0";
- socket_abstract = false;
- socket_pathname = false;
- };
-}
diff --git a/test/sandbox/case/tty.nix b/test/sandbox/case/tty.nix
deleted file mode 100644
index 4ba9360e..00000000
--- a/test/sandbox/case/tty.nix
+++ /dev/null
@@ -1,288 +0,0 @@
-{
- fs,
- ent,
- ignore,
- system,
-}:
-let
- extraPaths = {
- x86_64-linux = {
- fd = "fd0";
- "/dev/dri" = {
- by-path = fs "800001ed" {
- "pci-0000:00:09.0-card" = fs "80001ff" null null;
- "pci-0000:00:09.0-render" = fs "80001ff" null null;
- } null;
- card0 = fs "42001b0" null null;
- renderD128 = fs "42001b6" null null;
- };
- sr = {
- sr0 = fs "80001ff" null null;
- };
- };
- aarch64-linux = {
- fd = "mtdblock0";
- "/dev/dri" = null;
- sr = { };
- };
- };
-in
-{
- name = "tty";
- tty = true;
- device = false;
- mapRealUid = false;
- useCommonPaths = true;
- userns = false;
- x11 = true;
- hostAbstract = true;
- shareRuntime = true;
- shareTmpdir = false;
-
- # 0, PresetExt | PresetDenyNS | PresetDenyDevel
- expectedFilter = {
- x86_64-linux = "0b76007476c1c9e25dbf674c29fdf609a1656a70063e49327654e1b5360ad3da06e1a3e32bf80e961c5516ad83d4b9e7e9bde876a93797e27627d2555c25858b";
- aarch64-linux = "cf1f4dc87436ba8ec95d268b663a6397bb0b4a5ac64d8557e6cc529d8b0f6f65dad3a92b62ed29d85eee9c6dde1267757a4d0f86032e8a45ca1bceadfa34cf5e";
- };
-
- want = {
- env = [
- "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus"
- "DISPLAY=:0"
- "HOME=/var/lib/hakurei/u0/a2"
- "SHELL=/run/current-system/sw/bin/bash"
- "TERM=linux"
- "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 = fs "dead" {
- ".hakurei" = fs "800001ed" {
- ".ro-store" = fs "801001fd" null null;
- store = fs "800001ff" null null;
- } null;
- bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
- dev = fs "800001ed" {
- console = fs "4200190" null null;
- core = fs "80001ff" null null;
- dri = fs "800001ed" extraPaths.${system}."/dev/dri" null;
- fd = fs "80001ff" null null;
- full = fs "42001b6" null null;
- mqueue = fs "801001ff" { } null;
- null = fs "42001b6" null "";
- ptmx = fs "80001ff" null null;
- pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null;
- random = fs "42001b6" null null;
- shm = fs "801001ff" { } null;
- stderr = fs "80001ff" null null;
- stdin = fs "80001ff" null null;
- stdout = fs "80001ff" null null;
- tty = fs "42001b6" null null;
- urandom = fs "42001b6" null null;
- zero = fs "42001b6" null null;
- } null;
- etc = fs "800001ed" {
- ".clean" = fs "80001ff" null null;
- ".host" = fs "800001c0" null null;
- ".updated" = fs "80001ff" null null;
- "NIXOS" = fs "80001ff" null null;
- "X11" = fs "80001ff" null null;
- "alsa" = fs "80001ff" null null;
- "bash_logout" = fs "80001ff" null null;
- "bashrc" = fs "80001ff" null null;
- "binfmt.d" = fs "80001ff" null null;
- "dbus-1" = fs "80001ff" null null;
- "default" = fs "80001ff" null null;
- "dhcpcd.exit-hook" = fs "80001ff" null null;
- "environment.d" = fs "80001ff" null null;
- "fonts" = fs "80001ff" null null;
- "fstab" = fs "80001ff" null null;
- "hsurc" = fs "80001ff" null null;
- "fuse.conf" = fs "80001ff" null null;
- "gai.conf" = fs "80001ff" null null;
- "group" = fs "180" null "hakurei:x:65534:\n";
- "host.conf" = fs "80001ff" null null;
- "hostname" = fs "80001ff" null null;
- "hosts" = fs "80001ff" null null;
- "inputrc" = fs "80001ff" null null;
- "issue" = fs "80001ff" null null;
- "kbd" = fs "80001ff" null null;
- "locale.conf" = fs "80001ff" null null;
- "login.defs" = fs "80001ff" null null;
- "lsb-release" = fs "80001ff" null null;
- "lvm" = fs "80001ff" null null;
- "machine-id" = fs "80001ff" null null;
- "man_db.conf" = fs "80001ff" null null;
- "modprobe.d" = fs "80001ff" null null;
- "modules-load.d" = fs "80001ff" null null;
- "mtab" = fs "80001ff" null null;
- "nanorc" = fs "80001ff" null null;
- "netgroup" = fs "80001ff" null null;
- "nix" = fs "80001ff" null null;
- "nixos" = fs "80001ff" null null;
- "nscd.conf" = fs "80001ff" null null;
- "nsswitch.conf" = fs "80001ff" null null;
- "os-release" = fs "80001ff" null null;
- "pam" = fs "80001ff" null null;
- "pam.d" = fs "80001ff" null null;
- "passwd" = fs "180" null "u0_a2:x:65534:65534:Hakurei:/var/lib/hakurei/u0/a2:/run/current-system/sw/bin/bash\n";
- "pipewire" = fs "80001ff" null null;
- "pki" = fs "80001ff" null null;
- "polkit-1" = fs "80001ff" null null;
- "profile" = fs "80001ff" null null;
- "protocols" = fs "80001ff" null null;
- "resolv.conf" = fs "80001ff" null null;
- "resolvconf.conf" = fs "80001ff" null null;
- "rpc" = fs "80001ff" null null;
- "services" = fs "80001ff" null null;
- "set-environment" = fs "80001ff" null null;
- "shadow" = fs "80001ff" null null;
- "shells" = fs "80001ff" null null;
- "speech-dispatcher" = fs "80001ff" null null;
- "ssh" = fs "80001ff" null null;
- "ssl" = fs "80001ff" null null;
- "static" = fs "80001ff" null null;
- "subgid" = fs "80001ff" null null;
- "subuid" = fs "80001ff" null null;
- "sudoers" = fs "80001ff" null null;
- "sway" = fs "80001ff" null null;
- "sysctl.d" = fs "80001ff" null null;
- "systemd" = fs "80001ff" null null;
- "terminfo" = fs "80001ff" null null;
- "tmpfiles.d" = fs "80001ff" null null;
- "udev" = fs "80001ff" null null;
- "vconsole.conf" = fs "80001ff" null null;
- "xdg" = fs "80001ff" null null;
- "zoneinfo" = fs "80001ff" null null;
- } null;
- nix = fs "800001c0" { store = fs "801001fd" null null; } null;
- proc = fs "8000016d" null null;
- run = fs "800001ed" {
- current-system = fs "80001ff" null null;
- opengl-driver = fs "80001ff" null null;
- user = fs "800001ed" {
- "65534" = fs "800001f8" {
- bus = fs "10001fd" null null;
- pulse = fs "800001c0" { native = fs "10001ff" null null; } null;
- wayland-0 = fs "1000038" null null;
- } null;
- } null;
- } null;
- sys = fs "800001c0" {
- block = fs "800001ed" (
- {
- ${extraPaths.${system}.fd} = fs "80001ff" null null;
- loop0 = fs "80001ff" null null;
- loop1 = fs "80001ff" null null;
- loop2 = fs "80001ff" null null;
- loop3 = fs "80001ff" null null;
- loop4 = fs "80001ff" null null;
- loop5 = fs "80001ff" null null;
- loop6 = fs "80001ff" null null;
- loop7 = fs "80001ff" null null;
- vda = fs "80001ff" null null;
- }
- // extraPaths.${system}.sr
- ) null;
- bus = fs "800001ed" null null;
- class = fs "800001ed" null null;
- dev = fs "800001ed" {
- block = fs "800001ed" null null;
- char = fs "800001ed" null null;
- } null;
- devices = fs "800001ed" null null;
- } null;
- tmp = fs "801001ff" {
- ".X11-unix" = fs "801001ff" { X0 = fs "10001fd" null null; } null;
- } null;
- usr = fs "800001c0" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null;
- var = fs "800001c0" {
- tmp = fs "801001ff" null null;
- lib = fs "800001c0" {
- hakurei = fs "800001c0" {
- u0 = fs "800001c0" {
- a2 = fs "800001c0" {
- ".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
- ".config" = fs "800001ed" {
- "environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null;
- systemd = fs "800001ed" {
- user = fs "800001ed" { "tray.target" = fs "80001ff" null null; } null;
- } null;
- } null;
- ".local" = fs "800001ed" {
- state = fs "800001ed" {
- ".keep" = fs "80001ff" null "";
- home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
- nix = fs "800001ed" {
- profiles = fs "800001ed" {
- profile = fs "80001ff" null null;
- profile-1-link = fs "80001ff" null null;
- } null;
- } null;
- } null;
- } null;
- ".nix-defexpr" = fs "800001ed" {
- channels = fs "80001ff" null null;
- channels_root = fs "80001ff" null null;
- } null;
- ".nix-profile" = fs "80001ff" null null;
- } null;
- } null;
- } null;
- } null;
- cache = fs "800001ed" { private = fs "800001c0" null null; } null;
- } null;
- } null;
-
- mount = [
- (ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10002,gid=10002")
- (ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
- (ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=10002,gid=10002")
- (ent "/" "/dev" "ro,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=10002,gid=10002")
- (ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/random" "/dev/random" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/urandom" "/dev/urandom" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/tty" "/dev/tty" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/" "/dev/pts" "rw,nosuid,noexec,relatime" "devpts" "devpts" "rw,mode=620,ptmxmode=666")
- (ent ignore "/dev/console" "rw,nosuid,noexec,relatime" "devpts" "devpts" "rw,gid=3,mode=620,ptmxmode=666")
- (ent "/" "/dev/mqueue" "rw,nosuid,nodev,noexec,relatime" "mqueue" "mqueue" "rw")
- (ent "/" "/dev/shm" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=10002,gid=10002")
- (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=16384k,mode=755,uid=10002,gid=10002")
- (ent "/tmp/hakurei.0/runtime/2" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/tmp" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=10002,gid=10002")
- (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10002,gid=10002")
- (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=10002,gid=10002")
- (ent ignore "/run/user/65534/wayland-0" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/tmp/.X11-unix" "/tmp/.X11-unix" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/run/user/65534/bus" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/bin" "/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/usr/bin" "/usr/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/nix/store" "ro,nosuid,nodev,relatime" "overlay" "overlay" "rw,lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/upper,workdir=/sysroot/nix/.rw-store/work,uuid=on")
- (ent "/block" "/sys/block" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/bus" "/sys/bus" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/class" "/sys/class" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/dev" "/sys/dev" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/devices" "/sys/devices" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
- (ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
- (ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr")
- (ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,uuid=on,userxattr")
- (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent "/var/lib/hakurei/u0/a2" "/var/lib/hakurei/u0/a2" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- (ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
- ];
-
- seccomp = true;
-
- try_socket = "/tmp/.X11-unix/X0";
- socket_abstract = true;
- socket_pathname = true;
- };
-}
diff --git a/test/sandbox/configuration.nix b/test/sandbox/configuration.nix
deleted file mode 100644
index bc189f7d..00000000
--- a/test/sandbox/configuration.nix
+++ /dev/null
@@ -1,113 +0,0 @@
-{
- lib,
- pkgs,
- config,
- ...
-}:
-let
- testProgram = pkgs.callPackage ./tool/package.nix { inherit (config.environment.hakurei.package) version; };
- testCases = import ./case pkgs.stdenv.hostPlatform.system lib testProgram;
-in
-{
- users.users = {
- alice = {
- isNormalUser = true;
- description = "Alice Foobar";
- password = "foobar";
- uid = 1000;
- };
- };
-
- home-manager.users.alice.home.stateVersion = "24.11";
-
- # Automatically login on tty1 as a normal user:
- services.getty.autologinUser = "alice";
-
- environment = {
- systemPackages = [
- # For checking seccomp outcome:
- testProgram
-
- # For checking pd outcome:
- (pkgs.writeShellScriptBin "check-sandbox-pd" ''
- hakurei -v exec hakurei-test \
- -p "/var/tmp/.hakurei-check-ok.0" \
- -t ${toString (builtins.toFile "hakurei-pd-want.json" (builtins.toJSON testCases.pd.want))} \
- -s ${testCases.pd.expectedFilter.${pkgs.stdenv.hostPlatform.system}} "$@"
- '')
- ];
-
- variables = {
- SWAYSOCK = "/tmp/sway-ipc.sock";
- WLR_RENDERER = "pixman";
- };
- };
-
- # Automatically configure and start Sway when logging in on tty1:
- programs.bash.loginShellInit = ''
- if [ "$(tty)" = "/dev/tty1" ]; then
- set -e
-
- mkdir -p ~/.config/sway
- (sed s/Mod4/Mod1/ /etc/sway/config &&
- echo 'output * bg ${pkgs.nixos-artwork.wallpapers.simple-light-gray.gnomeFilePath} fill' &&
- echo 'output Virtual-1 res 1680x1050') > ~/.config/sway/config
-
- sway --validate
- systemd-cat --identifier=session sway && touch /tmp/sway-exit-ok
- fi
- '';
-
- programs.sway.enable = true;
-
- virtualisation.qemu.options = [
- # Need to switch to a different GPU driver than the default one (-vga std) so that Sway can launch:
- "-vga none -device virtio-gpu-pci"
-
- # Increase performance:
- "-smp 8"
- ];
-
- environment.hakurei = {
- enable = true;
- stateDir = "/var/lib/hakurei";
- users.alice = 0;
-
- extraHomeConfig = {
- home.stateVersion = "23.05";
- };
-
- commonPaths = [
- {
- type = "bind";
- src = "/var/tmp";
- write = true;
- }
- {
- type = "bind";
- src = "/var/cache";
- write = true;
- }
- {
- type = "overlay";
- dst = "/.hakurei/.ro-store";
- lower = [
- "/nix/.ro-store"
- "/nix/.rw-store/upper"
- ];
- }
- {
- type = "overlay";
- dst = "/.hakurei/store";
- lower = [
- "/nix/.ro-store"
- "/nix/.rw-store/upper"
- ];
- upper = "/tmp/.hakurei-store-rw/upper";
- work = "/tmp/.hakurei-store-rw/work";
- }
- ];
-
- inherit (testCases) apps;
- };
-}
diff --git a/test/sandbox/default.nix b/test/sandbox/default.nix
deleted file mode 100644
index 47a59de9..00000000
--- a/test/sandbox/default.nix
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- lib,
- testers,
-
- self,
- withRace ? false,
-}:
-
-testers.nixosTest {
- name = "hakurei-sandbox" + (if withRace then "-race" else "");
- nodes.machine =
- { options, pkgs, ... }:
- {
- # Run with Go race detector:
- environment.hakurei = lib.mkIf withRace rec {
- # race detector does not support static linking
- package = (pkgs.callPackage ../package.nix { }).overrideAttrs (previousAttrs: {
- env = previousAttrs.env // {
- GOFLAGS = previousAttrs.env.GOFLAGS + " -race";
- };
- });
- hsuPackage = options.environment.hakurei.hsuPackage.default.override { hakurei = package; };
- };
-
- imports = [
- ./configuration.nix
-
- self.nixosModules.hakurei
- self.inputs.home-manager.nixosModules.home-manager
- ];
- };
-
- # adapted from nixos sway integration tests
-
- # testScriptWithTypes:49: error: Cannot call function of unknown type
- # (machine.succeed if succeed else machine.execute)(
- # ^
- # Found 1 error in 1 file (checked 1 source file)
- skipTypeCheck = true;
- testScript = builtins.readFile ./test.py;
-}
diff --git a/test/sandbox/main.go b/test/sandbox/main.go
new file mode 100644
index 00000000..311b9f58
--- /dev/null
+++ b/test/sandbox/main.go
@@ -0,0 +1,410 @@
+//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,
+ username string,
+ files ...*os.File,
+) (pid int, done <-chan error) {
+ _serial := strconv.FormatUint(serial, 10)
+ _, done = testsuite.MustStartAs(
+ ctx, username, 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()
+ username := testsuite.GetUser().Username
+
+ // the signal handler does not wait for termination
+ ctx := context.Background()
+
+ 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.MustRunAs(
+ username, "-i",
+ "hakurei", "exec", "capsh", "--print",
+ )
+ wg.Go(func() {
+ defer log.Println("validated capabilities/securebits in user namespace")
+
+ testsuite.MustRunAs(
+ username, "-i",
+ "hakurei", "exec", "capsh", "--has-no-new-privs",
+ )
+
+ for _, p := range []byte{'a', 'b', 'i', 'p'} {
+ testsuite.MustFailAs(
+ username, "-i",
+ "hakurei", "exec", "capsh", "--has-"+string(p)+"=CAP_SYS_ADMIN",
+ )
+ }
+ testsuite.MustFailAs(
+ username, "-i",
+ "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(), username)
+ 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(), username, 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(username)
+ testsuite.MustStartSway(&swg, username, dbusEnv)
+ defer testsuite.TerminateSway(username)
+ testsuite.MustStartPipeWire(username, 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(
+ "sudo",
+ "-u", username,
+ "-C", "6",
+ "TERM=xterm",
+ testsuite.XDGRuntimeEnv,
+ testsuite.WaylandEnv,
+ "DISPLAY=:0",
+ dbusEnv,
+ "--",
+
+ "script", "/dev/null",
+ "-E", "always",
+ "-qec",
+ "hakurei run "+
+ "--identifier-fd=5"+
+ " 4 1>&3",
+ )
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Pdeathsig: syscall.SIGTERM,
+ }
+ var output bytes.Buffer
+ cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, &output, &output
+
+ 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
new file mode 100644
index 00000000..ddabc71e
--- /dev/null
+++ b/test/sandbox/seccomp.patch
@@ -0,0 +1,18 @@
+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/test.py b/test/sandbox/test.py
deleted file mode 100644
index a431daab..00000000
--- a/test/sandbox/test.py
+++ /dev/null
@@ -1,88 +0,0 @@
-import json
-import shlex
-
-q = shlex.quote
-
-
-def swaymsg(command: str = "", succeed=True, type="command"):
- assert command != "" or type != "command", "Must specify command or type"
- shell = q(f"swaymsg -t {q(type)} -- {q(command)}")
- with machine.nested(
- f"sending swaymsg {shell!r}" + " (allowed to fail)" * (not succeed)
- ):
- ret = (machine.succeed if succeed else machine.execute)(
- f"su - alice -c {shell}"
- )
-
- # execute also returns a status code, but disregard.
- if not succeed:
- _, ret = ret
-
- if not succeed and not ret:
- return None
-
- parsed = json.loads(ret)
- return parsed
-
-
-def check_filter(check_offset, name, pname):
- pid = int(machine.wait_until_succeeds(f"pgrep -U {10000+check_offset} -x {pname}"))
- hash = machine.succeed(f"sudo -u alice -i XDG_RUNTIME_DIR=/run/user/1000 WAYLAND_DISPLAY=wayland-1 check-sandbox-{name} hash")
- print(machine.succeed(f"hakurei-test -s {hash} filter {pid}"))
-
-
-start_all()
-machine.wait_for_unit("multi-user.target")
-
-# To check hakurei's version:
-print(machine.succeed("sudo -u alice -i hakurei version"))
-
-# Wait for Sway to complete startup:
-machine.wait_for_file("/run/user/1000/wayland-1")
-machine.wait_for_file("/tmp/sway-ipc.sock")
-
-# Check pd seccomp outcome:
-swaymsg("exec hakurei exec cat")
-check_filter(0, "pdlike", "cat")
-
-# Check fd leak:
-swaymsg("exec exec 127</proc/cmdline && hakurei -v exec sleep infinity")
-pd_identity0_sleep_pid = int(machine.wait_until_succeeds("pgrep -U 10000 -x sleep"))
-print(machine.succeed(f"hakurei-test fd {pd_identity0_sleep_pid}"))
-machine.succeed(f"kill -INT {pd_identity0_sleep_pid}")
-
-# Verify capabilities/securebits in user namespace:
-print(machine.succeed("sudo -u alice -i hakurei exec capsh --print"))
-print(machine.succeed("sudo -u alice -i hakurei exec capsh --has-no-new-privs"))
-print(machine.fail("sudo -u alice -i hakurei exec capsh --has-a=CAP_SYS_ADMIN"))
-print(machine.fail("sudo -u alice -i hakurei exec capsh --has-b=CAP_SYS_ADMIN"))
-print(machine.fail("sudo -u alice -i hakurei exec capsh --has-i=CAP_SYS_ADMIN"))
-print(machine.fail("sudo -u alice -i hakurei exec capsh --has-p=CAP_SYS_ADMIN"))
-print(machine.fail("sudo -u alice -i hakurei exec umount -R /dev"))
-
-# Check sandbox outcome:
-machine.succeed("install -dm0777 /tmp/.hakurei-store-rw/{upper,work}")
-check_offset = 0
-def check_sandbox(name):
- global check_offset
- swaymsg(f"exec script /dev/null -E always -qec check-sandbox-{name}")
- machine.wait_for_file(f"/var/tmp/.hakurei-check-ok.{check_offset}")
- check_filter(check_offset, name, "hakurei-test")
- check_offset += 1
-
-
-check_sandbox("pd")
-check_sandbox("preset")
-check_sandbox("tty")
-check_sandbox("mapuid")
-check_sandbox("device")
-check_sandbox("pdlike")
-
-# Exit Sway and verify process exit status 0:
-machine.wait_until_fails("pgrep -x hakurei")
-swaymsg("exit", succeed=False)
-machine.wait_for_file("/tmp/sway-exit-ok")
-
-# Print hakurei runDir contents:
-print(machine.fail("ls /run/user/1000/hakurei"))
-machine.succeed("find /tmp -maxdepth 1 -type d -name '.hakurei-shim-*' -print -exec false '{}' +")
diff --git a/test/sandbox/testdata/device.go b/test/sandbox/testdata/device.go
new file mode 100644
index 00000000..89feb819
--- /dev/null
+++ b/test/sandbox/testdata/device.go
@@ -0,0 +1,134 @@
+//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
new file mode 100644
index 00000000..fad4ec36
--- /dev/null
+++ b/test/sandbox/testdata/mapuid.go
@@ -0,0 +1,124 @@
+//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:1000:Hakurei:/.hakurei:/usr/bin/bash\n")},
+ "group": {Mode: 0600,
+ Data: new("hakurei:x:1000:\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
new file mode 100644
index 00000000..53d8062a
--- /dev/null
+++ b/test/sandbox/testdata/pdlike.go
@@ -0,0 +1,141 @@
+//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
new file mode 100644
index 00000000..c410e626
--- /dev/null
+++ b/test/sandbox/testdata/simple.go
@@ -0,0 +1,140 @@
+//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
new file mode 100644
index 00000000..e4e8643a
--- /dev/null
+++ b/test/sandbox/testdata/sum.go
@@ -0,0 +1,22 @@
+//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
new file mode 100644
index 00000000..bd751105
--- /dev/null
+++ b/test/sandbox/testdata/sum_amd64.go
@@ -0,0 +1,9 @@
+//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
new file mode 100644
index 00000000..1691828f
--- /dev/null
+++ b/test/sandbox/testdata/sum_arm64.go
@@ -0,0 +1,9 @@
+//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
new file mode 100644
index 00000000..3418d8ae
--- /dev/null
+++ b/test/sandbox/testdata/testdata.go
@@ -0,0 +1,125 @@
+//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
new file mode 100644
index 00000000..4788f484
--- /dev/null
+++ b/test/sandbox/testdata/tty.go
@@ -0,0 +1,145 @@
+//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
new file mode 100644
index 00000000..0782a5e0
--- /dev/null
+++ b/test/sandbox/tester/main.go
@@ -0,0 +1,224 @@
+//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
+}
diff --git a/test/sandbox/tool/main.go b/test/sandbox/tool/main.go
deleted file mode 100644
index 889142d4..00000000
--- a/test/sandbox/tool/main.go
+++ /dev/null
@@ -1,106 +0,0 @@
-//go:build testtool
-
-package main
-
-import (
- "flag"
- "fmt"
- "log"
- "os"
- "os/signal"
- "strconv"
- "strings"
- "syscall"
-
- "hakurei.app/test/internal/sandbox"
-)
-
-var (
- flagMarkerPath string
- flagTestCase string
- flagBpfHash string
-)
-
-func init() {
- flag.StringVar(&flagMarkerPath, "p", "/tmp/sandbox-ok", "Pathname of completion marker")
- flag.StringVar(&flagTestCase, "t", "", "Nix store path to test case file")
- flag.StringVar(&flagBpfHash, "s", "", "String representation of expected bpf sha512 hash")
-}
-
-func main() {
- log.SetFlags(0)
- log.SetPrefix("test: ")
- flag.Parse()
-
- args := flag.Args()
- if len(args) < 1 {
- s := make(chan os.Signal, 1)
- signal.Notify(s, syscall.SIGINT)
- go func() { <-s; log.Println("exiting on signal (likely from verifier)"); os.Exit(0) }()
-
- (&sandbox.T{FS: os.DirFS("/")}).MustCheckFile(flagTestCase)
- if _, err := os.Create(flagMarkerPath); err != nil {
- log.Fatalf("cannot create success marker: %v", err)
- }
- log.Printf("blocking for seccomp check (%s)", flagMarkerPath)
- select {}
- return
- }
-
- switch args[0] {
- case "filter":
- if len(args) != 2 {
- log.Fatal("invalid argument")
- }
-
- if pid, err := strconv.Atoi(strings.TrimSpace(args[1])); err != nil {
- log.Fatalf("%s", err)
- } else if pid < 1 {
- log.Fatalf("%d out of range", pid)
- } else {
- sandbox.MustCheckFilter(pid, flagBpfHash)
- if err = syscall.Kill(pid, syscall.SIGINT); err != nil {
- log.Fatalf("cannot signal check process: %v", err)
- }
- }
-
- case "hash": // this eases the pain of passing the hash to python
- fmt.Print(flagBpfHash)
-
- case "fd":
- if len(args) != 2 {
- log.Fatal("invalid argument")
- }
- prefix := fmt.Sprintf("/proc/%s/fd/", args[1])
-
- 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(prefix + ent.Name()); err != nil {
- log.Fatal(err.Error())
- }
- log.Printf("[FAIL] extra fd %d -> %s", fd, d)
- }
- }
- if fail {
- log.Fatal("[FAIL] file descriptors leaked")
- }
-
- default:
- log.Fatal("invalid argument")
- }
-}
diff --git a/test/sandbox/tool/package.nix b/test/sandbox/tool/package.nix
deleted file mode 100644
index bd57b432..00000000
--- a/test/sandbox/tool/package.nix
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- lib,
- buildGoModule,
- pkg-config,
- util-linux,
-
- version,
-}:
-buildGoModule rec {
- pname = "check-sandbox";
- inherit version;
-
- src = builtins.path {
- name = "${pname}-src";
- path = lib.cleanSource ../../.;
- filter = path: type: (type == "directory") || (type == "regular" && lib.hasSuffix ".go" path);
- };
- vendorHash = null;
-
- tags = [ "testtool" "tester" ];
-
- buildInputs = [ util-linux ];
- nativeBuildInputs = [ pkg-config ];
-
- preBuild = ''
- go mod init hakurei.app/test >& /dev/null
- '';
-
- postInstall = ''
- mv $out/bin/tool $out/bin/hakurei-test
- '';
-}