diff --git a/cmd/hakurei/command.go b/cmd/hakurei/command.go index 0c2cb53..851e0d0 100644 --- a/cmd/hakurei/command.go +++ b/cmd/hakurei/command.go @@ -16,6 +16,7 @@ import ( "hakurei.app/command" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/internal" "hakurei.app/internal/app" @@ -107,7 +108,7 @@ func buildCommand(ctx context.Context, msg container.Msg, early *earlyHardeningE // paths are identical, resolve inner shell and program path shell := container.AbsFHSRoot.Append("bin", "sh") - if a, err := container.NewAbs(os.Getenv("SHELL")); err == nil { + if a, err := check.NewAbs(os.Getenv("SHELL")); err == nil { shell = a } progPath := shell @@ -115,7 +116,7 @@ func buildCommand(ctx context.Context, msg container.Msg, early *earlyHardeningE if p, err := exec.LookPath(args[0]); err != nil { log.Fatal(errors.Unwrap(err)) return err - } else if progPath, err = container.NewAbs(p); err != nil { + } else if progPath, err = check.NewAbs(p); err != nil { log.Fatal(err.Error()) return err } @@ -201,7 +202,7 @@ func buildCommand(ctx context.Context, msg container.Msg, early *earlyHardeningE passwdOnce.Do(passwdFunc) homeDir = passwd.HomeDir } - if a, err := container.NewAbs(homeDir); err != nil { + if a, err := check.NewAbs(homeDir); err != nil { log.Fatal(err.Error()) return err } else { diff --git a/cmd/hpkg/app.go b/cmd/hpkg/app.go index da1fd30..d0092d1 100644 --- a/cmd/hpkg/app.go +++ b/cmd/hpkg/app.go @@ -6,6 +6,7 @@ import ( "os" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" ) @@ -54,14 +55,14 @@ type appInfo struct { // store path to nixGL source NixGL string `json:"nix_gl,omitempty"` // store path to activate-and-exec script - Launcher *container.Absolute `json:"launcher"` + Launcher *check.Absolute `json:"launcher"` // store path to /run/current-system - CurrentSystem *container.Absolute `json:"current_system"` + CurrentSystem *check.Absolute `json:"current_system"` // store path to home-manager activation package ActivationPackage string `json:"activation_package"` } -func (app *appInfo) toHst(pathSet *appPathSet, pathname *container.Absolute, argv []string, flagDropShell bool) *hst.Config { +func (app *appInfo) toHst(pathSet *appPathSet, pathname *check.Absolute, argv []string, flagDropShell bool) *hst.Config { config := &hst.Config{ ID: app.ID, diff --git a/cmd/hpkg/main.go b/cmd/hpkg/main.go index 03247aa..dde0ca2 100644 --- a/cmd/hpkg/main.go +++ b/cmd/hpkg/main.go @@ -12,6 +12,7 @@ import ( "hakurei.app/command" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" ) @@ -79,11 +80,11 @@ func main() { Extract package and set up for cleanup. */ - var workDir *container.Absolute + var workDir *check.Absolute if p, err := os.MkdirTemp("", "hpkg.*"); err != nil { log.Printf("cannot create temporary directory: %v", err) return err - } else if workDir, err = container.NewAbs(p); err != nil { + } else if workDir, err = check.NewAbs(p); err != nil { log.Printf("invalid temporary directory: %v", err) return err } diff --git a/cmd/hpkg/paths.go b/cmd/hpkg/paths.go index ee4b7e7..c1d9ae3 100644 --- a/cmd/hpkg/paths.go +++ b/cmd/hpkg/paths.go @@ -8,18 +8,19 @@ import ( "sync/atomic" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" ) const bash = "bash" var ( - dataHome *container.Absolute + dataHome *check.Absolute ) func init() { // dataHome - if a, err := container.NewAbs(os.Getenv("HAKUREI_DATA_HOME")); err == nil { + if a, err := check.NewAbs(os.Getenv("HAKUREI_DATA_HOME")); err == nil { dataHome = a } else { dataHome = container.AbsFHSVarLib.Append("hakurei/" + strconv.Itoa(os.Getuid())) @@ -29,13 +30,13 @@ func init() { var ( pathBin = container.AbsFHSRoot.Append("bin") - pathNix = container.MustAbs("/nix/") + pathNix = check.MustAbs("/nix/") pathNixStore = pathNix.Append("store/") pathCurrentSystem = container.AbsFHSRun.Append("current-system") pathSwBin = pathCurrentSystem.Append("sw/bin/") pathShell = pathSwBin.Append(bash) - pathData = container.MustAbs("/data") + pathData = check.MustAbs("/data") pathDataData = pathData.Append("data") ) @@ -64,15 +65,15 @@ func mustRun(msg container.Msg, name string, arg ...string) { type appPathSet struct { // ${dataHome}/${id} - baseDir *container.Absolute + baseDir *check.Absolute // ${baseDir}/app - metaPath *container.Absolute + metaPath *check.Absolute // ${baseDir}/files - homeDir *container.Absolute + homeDir *check.Absolute // ${baseDir}/cache - cacheDir *container.Absolute + cacheDir *check.Absolute // ${baseDir}/cache/nix - nixPath *container.Absolute + nixPath *check.Absolute } func pathSetByApp(id string) *appPathSet { diff --git a/cmd/hpkg/with.go b/cmd/hpkg/with.go index b3ccd47..99de04d 100644 --- a/cmd/hpkg/with.go +++ b/cmd/hpkg/with.go @@ -6,6 +6,7 @@ import ( "strings" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" ) @@ -63,7 +64,7 @@ func withNixDaemon( func withCacheDir( ctx context.Context, msg container.Msg, - action string, command []string, workDir *container.Absolute, + action string, command []string, workDir *check.Absolute, app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) { mustRunAppDropShell(ctx, msg, &hst.Config{ ID: app.ID, diff --git a/container/autoetc.go b/container/autoetc.go index 9a58740..295bdf7 100644 --- a/container/autoetc.go +++ b/container/autoetc.go @@ -3,13 +3,15 @@ package container import ( "encoding/gob" "fmt" + + "hakurei.app/container/check" ) func init() { gob.Register(new(AutoEtcOp)) } // Etc appends an [Op] that expands host /etc into a toplevel symlink mirror with /etc semantics. // This is not a generic setup op. It is implemented here to reduce ipc overhead. -func (f *Ops) Etc(host *Absolute, prefix string) *Ops { +func (f *Ops) Etc(host *check.Absolute, prefix string) *Ops { e := &AutoEtcOp{prefix} f.Mkdir(AbsFHSEtc, 0755) f.Bind(host, e.hostPath(), 0) @@ -57,8 +59,8 @@ func (e *AutoEtcOp) apply(state *setupState, k syscallDispatcher) error { return nil } -func (e *AutoEtcOp) hostPath() *Absolute { return AbsFHSEtc.Append(e.hostRel()) } -func (e *AutoEtcOp) hostRel() string { return ".host/" + e.Prefix } +func (e *AutoEtcOp) hostPath() *check.Absolute { return AbsFHSEtc.Append(e.hostRel()) } +func (e *AutoEtcOp) hostRel() string { return ".host/" + e.Prefix } func (e *AutoEtcOp) Is(op Op) bool { ve, ok := op.(*AutoEtcOp) diff --git a/container/autoetc_test.go b/container/autoetc_test.go index 58ef99b..30f46e5 100644 --- a/container/autoetc_test.go +++ b/container/autoetc_test.go @@ -5,6 +5,7 @@ import ( "os" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" ) @@ -256,11 +257,11 @@ func TestAutoEtcOp(t *testing.T) { }) checkOpsBuilder(t, []opsBuilderTestCase{ - {"pd", new(Ops).Etc(MustAbs("/etc/"), "048090b6ed8f9ebb10e275ff5d8c0659"), Ops{ - &MkdirOp{Path: MustAbs("/etc/"), Perm: 0755}, + {"pd", new(Ops).Etc(check.MustAbs("/etc/"), "048090b6ed8f9ebb10e275ff5d8c0659"), Ops{ + &MkdirOp{Path: check.MustAbs("/etc/"), Perm: 0755}, &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), }, &AutoEtcOp{Prefix: "048090b6ed8f9ebb10e275ff5d8c0659"}, }}, diff --git a/container/autoroot.go b/container/autoroot.go index ee8bcbd..519aada 100644 --- a/container/autoroot.go +++ b/container/autoroot.go @@ -3,19 +3,21 @@ package container import ( "encoding/gob" "fmt" + + "hakurei.app/container/check" ) func init() { gob.Register(new(AutoRootOp)) } // Root appends an [Op] that expands a directory into a toplevel bind mount mirror on container root. // This is not a generic setup op. It is implemented here to reduce ipc overhead. -func (f *Ops) Root(host *Absolute, flags int) *Ops { +func (f *Ops) Root(host *check.Absolute, flags int) *Ops { *f = append(*f, &AutoRootOp{host, flags, nil}) return f } type AutoRootOp struct { - Host *Absolute + Host *check.Absolute // passed through to bindMount Flags int diff --git a/container/autoroot_test.go b/container/autoroot_test.go index fe66222..fed1ab1 100644 --- a/container/autoroot_test.go +++ b/container/autoroot_test.go @@ -5,6 +5,7 @@ import ( "os" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" ) @@ -18,14 +19,14 @@ func TestAutoRootOp(t *testing.T) { checkOpBehaviour(t, []opBehaviourTestCase{ {"readdir", &Params{ParentPerm: 0750}, &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, }, []stub.Call{ call("readdir", stub.ExpectArgs{"/"}, stubDir(), stub.UniqueError(2)), }, stub.UniqueError(2), nil, nil}, {"early", &Params{ParentPerm: 0750}, &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, }, []stub.Call{ call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64", @@ -34,7 +35,7 @@ func TestAutoRootOp(t *testing.T) { }, stub.UniqueError(1), nil, nil}, {"apply", &Params{ParentPerm: 0750}, &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, }, []stub.Call{ call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64", @@ -55,7 +56,7 @@ func TestAutoRootOp(t *testing.T) { }, stub.UniqueError(0)}, {"success pd", &Params{ParentPerm: 0750}, &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, }, []stub.Call{ call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64", @@ -86,7 +87,7 @@ func TestAutoRootOp(t *testing.T) { }, nil}, {"success", &Params{ParentPerm: 0750}, &AutoRootOp{ - Host: MustAbs("/var/lib/planterette/base/debian:f92c9052"), + Host: check.MustAbs("/var/lib/planterette/base/debian:f92c9052"), }, []stub.Call{ call("readdir", stub.ExpectArgs{"/var/lib/planterette/base/debian:f92c9052"}, stubDir("bin", "dev", "etc", "home", "lib64", "lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil), @@ -119,13 +120,13 @@ func TestAutoRootOp(t *testing.T) { checkOpsValid(t, []opValidTestCase{ {"nil", (*AutoRootOp)(nil), false}, {"zero", new(AutoRootOp), false}, - {"valid", &AutoRootOp{Host: MustAbs("/")}, true}, + {"valid", &AutoRootOp{Host: check.MustAbs("/")}, true}, }) checkOpsBuilder(t, []opsBuilderTestCase{ - {"pd", new(Ops).Root(MustAbs("/"), BindWritable), Ops{ + {"pd", new(Ops).Root(check.MustAbs("/"), BindWritable), Ops{ &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, }, }}, @@ -135,42 +136,42 @@ func TestAutoRootOp(t *testing.T) { {"zero", new(AutoRootOp), new(AutoRootOp), false}, {"internal ne", &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, }, &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, resolved: []*BindMountOp{new(BindMountOp)}, }, true}, {"flags differs", &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable | BindDevice, }, &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, }, false}, {"host differs", &AutoRootOp{ - Host: MustAbs("/tmp/"), + Host: check.MustAbs("/tmp/"), Flags: BindWritable, }, &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, }, false}, {"equals", &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, }, &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, }, true}, }) checkOpMeta(t, []opMetaTestCase{ {"root", &AutoRootOp{ - Host: MustAbs("/"), + Host: check.MustAbs("/"), Flags: BindWritable, }, "setting up", `auto root "/" flags 0x2`}, }) diff --git a/container/absolute.go b/container/check/absolute.go similarity index 77% rename from container/absolute.go rename to container/check/absolute.go index 637b035..83ae8cc 100644 --- a/container/absolute.go +++ b/container/check/absolute.go @@ -1,4 +1,5 @@ -package container +// Package check provides types yielding values checked to meet a condition. +package check import ( "encoding/json" @@ -11,9 +12,7 @@ import ( ) // AbsoluteError is returned by [NewAbs] and holds the invalid pathname. -type AbsoluteError struct { - Pathname string -} +type AbsoluteError struct{ Pathname string } func (e *AbsoluteError) Error() string { return fmt.Sprintf("path %q is not absolute", e.Pathname) } func (e *AbsoluteError) Is(target error) bool { @@ -25,15 +24,13 @@ func (e *AbsoluteError) Is(target error) bool { } // Absolute holds a pathname checked to be absolute. -type Absolute struct { - pathname string -} +type Absolute struct{ pathname string } -// isAbs wraps [path.IsAbs] in case additional checks are added in the future. -func isAbs(pathname string) bool { return path.IsAbs(pathname) } +// unsafeAbs returns [check.Absolute] on any string value. +func unsafeAbs(pathname string) *Absolute { return &Absolute{pathname} } func (a *Absolute) String() string { - if a.pathname == zeroString { + if a.pathname == "" { panic("attempted use of zero Absolute") } return a.pathname @@ -44,16 +41,16 @@ func (a *Absolute) Is(v *Absolute) bool { return true } return a != nil && v != nil && - a.pathname != zeroString && v.pathname != zeroString && + a.pathname != "" && v.pathname != "" && a.pathname == v.pathname } // NewAbs checks pathname and returns a new [Absolute] if pathname is absolute. func NewAbs(pathname string) (*Absolute, error) { - if !isAbs(pathname) { + if !path.IsAbs(pathname) { return nil, &AbsoluteError{pathname} } - return &Absolute{pathname}, nil + return unsafeAbs(pathname), nil } // MustAbs calls [NewAbs] and panics on error. @@ -67,16 +64,16 @@ func MustAbs(pathname string) *Absolute { // Append calls [path.Join] with [Absolute] as the first element. func (a *Absolute) Append(elem ...string) *Absolute { - return &Absolute{path.Join(append([]string{a.String()}, elem...)...)} + return unsafeAbs(path.Join(append([]string{a.String()}, elem...)...)) } // Dir calls [path.Dir] with [Absolute] as its argument. -func (a *Absolute) Dir() *Absolute { return &Absolute{path.Dir(a.String())} } +func (a *Absolute) Dir() *Absolute { return unsafeAbs(path.Dir(a.String())) } func (a *Absolute) GobEncode() ([]byte, error) { return []byte(a.String()), nil } func (a *Absolute) GobDecode(data []byte) error { pathname := string(data) - if !isAbs(pathname) { + if !path.IsAbs(pathname) { return &AbsoluteError{pathname} } a.pathname = pathname @@ -89,7 +86,7 @@ func (a *Absolute) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &pathname); err != nil { return err } - if !isAbs(pathname) { + if !path.IsAbs(pathname) { return &AbsoluteError{pathname} } a.pathname = pathname diff --git a/container/absolute_test.go b/container/check/absolute_test.go similarity index 97% rename from container/absolute_test.go rename to container/check/absolute_test.go index e04ad5c..a25c0ad 100644 --- a/container/absolute_test.go +++ b/container/check/absolute_test.go @@ -1,4 +1,4 @@ -package container +package check_test import ( "bytes" @@ -9,8 +9,14 @@ import ( "strings" "syscall" "testing" + _ "unsafe" + + . "hakurei.app/container/check" ) +//go:linkname unsafeAbs hakurei.app/container/check.unsafeAbs +func unsafeAbs(_ string) *Absolute + func TestAbsoluteError(t *testing.T) { testCases := []struct { name string @@ -80,7 +86,7 @@ func TestNewAbs(t *testing.T) { func TestAbsoluteString(t *testing.T) { t.Run("passthrough", func(t *testing.T) { pathname := "/etc" - if got := (&Absolute{pathname}).String(); got != pathname { + if got := unsafeAbs(pathname).String(); got != pathname { t.Errorf("String: %q, want %q", got, pathname) } }) diff --git a/container/container.go b/container/container.go index e54afb9..08dc9e4 100644 --- a/container/container.go +++ b/container/container.go @@ -15,6 +15,7 @@ import ( "time" "hakurei.app/container/bits" + "hakurei.app/container/check" "hakurei.app/container/seccomp" ) @@ -57,11 +58,11 @@ type ( // Params holds container configuration and is safe to serialise. Params struct { // Working directory in the container. - Dir *Absolute + Dir *check.Absolute // Initial process environment. Env []string // Pathname of initial process in the container. - Path *Absolute + Path *check.Absolute // Initial process argv. Args []string // Deliver SIGINT to the initial process on context cancellation. @@ -407,7 +408,7 @@ func New(ctx context.Context, msg Msg) *Container { } // NewCommand calls [New] and initialises the [Params.Path] and [Params.Args] fields. -func NewCommand(ctx context.Context, msg Msg, pathname *Absolute, name string, args ...string) *Container { +func NewCommand(ctx context.Context, msg Msg, pathname *check.Absolute, name string, args ...string) *Container { z := New(ctx, msg) z.Path = pathname z.Args = append([]string{name}, args...) diff --git a/container/container_test.go b/container/container_test.go index 762b147..2d60f29 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -21,6 +21,7 @@ import ( "hakurei.app/command" "hakurei.app/container" "hakurei.app/container/bits" + "hakurei.app/container/check" "hakurei.app/container/seccomp" "hakurei.app/container/vfs" "hakurei.app/hst" @@ -226,7 +227,7 @@ var containerTestCases = []struct { {"dev", true, true /* go test output is not a tty */, false, false, earlyOps(new(container.Ops). - Dev(container.MustAbs("/dev"), true), + Dev(check.MustAbs("/dev"), true), ), earlyMnt( ent("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", ignore), @@ -244,7 +245,7 @@ var containerTestCases = []struct { {"dev no mqueue", true, true /* go test output is not a tty */, false, false, earlyOps(new(container.Ops). - Dev(container.MustAbs("/dev"), false), + Dev(check.MustAbs("/dev"), false), ), earlyMnt( ent("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", ignore), @@ -261,13 +262,13 @@ var containerTestCases = []struct { {"overlay", true, false, false, true, func(t *testing.T) (*container.Ops, context.Context) { - tempDir := container.MustAbs(t.TempDir()) + tempDir := check.MustAbs(t.TempDir()) lower0, lower1, upper, work := tempDir.Append("lower0"), tempDir.Append("lower1"), tempDir.Append("upper"), tempDir.Append("work") - for _, a := range []*container.Absolute{lower0, lower1, upper, work} { + for _, a := range []*check.Absolute{lower0, lower1, upper, work} { if err := os.Mkdir(a.String(), 0755); err != nil { t.Fatalf("Mkdir: error = %v", err) } @@ -285,12 +286,12 @@ var containerTestCases = []struct { return []*vfs.MountInfoEntry{ ent("/", hst.Tmp, "rw", "overlay", "overlay", "rw,lowerdir="+ - container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*container.Absolute).String())+":"+ - container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*container.Absolute).String())+ + container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*check.Absolute).String())+":"+ + container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*check.Absolute).String())+ ",upperdir="+ - container.InternalToHostOvlEscape(ctx.Value(testVal("upper")).(*container.Absolute).String())+ + container.InternalToHostOvlEscape(ctx.Value(testVal("upper")).(*check.Absolute).String())+ ",workdir="+ - container.InternalToHostOvlEscape(ctx.Value(testVal("work")).(*container.Absolute).String())+ + container.InternalToHostOvlEscape(ctx.Value(testVal("work")).(*check.Absolute).String())+ ",redirect_dir=nofollow,uuid=on,userxattr"), } }, @@ -298,11 +299,11 @@ var containerTestCases = []struct { {"overlay ephemeral", true, false, false, true, func(t *testing.T) (*container.Ops, context.Context) { - tempDir := container.MustAbs(t.TempDir()) + tempDir := check.MustAbs(t.TempDir()) lower0, lower1 := tempDir.Append("lower0"), tempDir.Append("lower1") - for _, a := range []*container.Absolute{lower0, lower1} { + for _, a := range []*check.Absolute{lower0, lower1} { if err := os.Mkdir(a.String(), 0755); err != nil { t.Fatalf("Mkdir: error = %v", err) } @@ -322,11 +323,11 @@ var containerTestCases = []struct { {"overlay readonly", true, false, false, true, func(t *testing.T) (*container.Ops, context.Context) { - tempDir := container.MustAbs(t.TempDir()) + tempDir := check.MustAbs(t.TempDir()) lower0, lower1 := tempDir.Append("lower0"), tempDir.Append("lower1") - for _, a := range []*container.Absolute{lower0, lower1} { + for _, a := range []*check.Absolute{lower0, lower1} { if err := os.Mkdir(a.String(), 0755); err != nil { t.Fatalf("Mkdir: error = %v", err) } @@ -341,8 +342,8 @@ var containerTestCases = []struct { return []*vfs.MountInfoEntry{ ent("/", hst.Tmp, "rw", "overlay", "overlay", "ro,lowerdir="+ - container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*container.Absolute).String())+":"+ - container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*container.Absolute).String())+ + container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*check.Absolute).String())+":"+ + container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*check.Absolute).String())+ ",redirect_dir=nofollow,userxattr"), } }, @@ -389,7 +390,7 @@ func TestContainer(t *testing.T) { ctx, cancel := context.WithTimeout(t.Context(), helperDefaultTimeout) defer cancel() - var libPaths []*container.Absolute + var libPaths []*check.Absolute c := helperNewContainerLibPaths(ctx, &libPaths, "container", strconv.Itoa(i)) c.Uid = tc.uid c.Gid = tc.gid @@ -410,11 +411,11 @@ func TestContainer(t *testing.T) { c.HostNet = tc.net c. - Readonly(container.MustAbs(pathReadonly), 0755). - Tmpfs(container.MustAbs("/tmp"), 0, 0755). - Place(container.MustAbs("/etc/hostname"), []byte(c.Hostname)) + Readonly(check.MustAbs(pathReadonly), 0755). + Tmpfs(check.MustAbs("/tmp"), 0, 0755). + Place(check.MustAbs("/etc/hostname"), []byte(c.Hostname)) // needs /proc to check mountinfo - c.Proc(container.MustAbs("/proc")) + c.Proc(check.MustAbs("/proc")) // mountinfo cannot be resolved directly by helper due to libPaths nondeterminism mnt := make([]*vfs.MountInfoEntry, 0, 3+len(libPaths)) @@ -445,10 +446,10 @@ func TestContainer(t *testing.T) { _, _ = output.WriteTo(os.Stdout) t.Fatalf("cannot serialise expected mount points: %v", err) } - c.Place(container.MustAbs(pathWantMnt), want.Bytes()) + c.Place(check.MustAbs(pathWantMnt), want.Bytes()) if tc.ro { - c.Remount(container.MustAbs("/"), syscall.MS_RDONLY) + c.Remount(check.MustAbs("/"), syscall.MS_RDONLY) } if err := c.Start(); err != nil { @@ -545,7 +546,7 @@ func testContainerCancel( func TestContainerString(t *testing.T) { msg := container.NewMsg(nil) - c := container.NewCommand(t.Context(), msg, container.MustAbs("/run/current-system/sw/bin/ldd"), "ldd", "/usr/bin/env") + c := container.NewCommand(t.Context(), msg, check.MustAbs("/run/current-system/sw/bin/ldd"), "ldd", "/usr/bin/env") c.SeccompFlags |= seccomp.AllowMultiarch c.SeccompRules = seccomp.Preset( bits.PresetExt|bits.PresetDenyNS|bits.PresetDenyTTY, @@ -681,7 +682,7 @@ const ( ) var ( - absHelperInnerPath = container.MustAbs(helperInnerPath) + absHelperInnerPath = check.MustAbs(helperInnerPath) ) var helperCommands []func(c command.Command) @@ -709,11 +710,11 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -func helperNewContainerLibPaths(ctx context.Context, libPaths *[]*container.Absolute, args ...string) (c *container.Container) { +func helperNewContainerLibPaths(ctx context.Context, libPaths *[]*check.Absolute, args ...string) (c *container.Container) { msg := container.NewMsg(nil) c = container.NewCommand(ctx, msg, absHelperInnerPath, "helper", args...) c.Env = append(c.Env, envDoCheck+"=1") - c.Bind(container.MustAbs(os.Args[0]), absHelperInnerPath, 0) + c.Bind(check.MustAbs(os.Args[0]), absHelperInnerPath, 0) // in case test has cgo enabled if entries, err := ldd.Exec(ctx, msg, os.Args[0]); err != nil { @@ -729,5 +730,5 @@ func helperNewContainerLibPaths(ctx context.Context, libPaths *[]*container.Abso } func helperNewContainer(ctx context.Context, args ...string) (c *container.Container) { - return helperNewContainerLibPaths(ctx, new([]*container.Absolute), args...) + return helperNewContainerLibPaths(ctx, new([]*check.Absolute), args...) } diff --git a/container/errors.go b/container/errors.go index f4198b0..e3f4b9d 100644 --- a/container/errors.go +++ b/container/errors.go @@ -5,6 +5,7 @@ import ( "os" "syscall" + "hakurei.app/container/check" "hakurei.app/container/vfs" ) @@ -16,7 +17,7 @@ func messageFromError(err error) (string, bool) { if m, ok := messagePrefixP[os.PathError]("cannot ", err); ok { return m, ok } - if m, ok := messagePrefixP[AbsoluteError]("", err); ok { + if m, ok := messagePrefixP[check.AbsoluteError]("", err); ok { return m, ok } if m, ok := messagePrefix[OpRepeatError]("", err); ok { diff --git a/container/errors_test.go b/container/errors_test.go index fd774a4..c2d3fa7 100644 --- a/container/errors_test.go +++ b/container/errors_test.go @@ -8,6 +8,7 @@ import ( "syscall" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" "hakurei.app/container/vfs" ) @@ -34,7 +35,7 @@ func TestMessageFromError(t *testing.T) { Err: stub.UniqueError(0xdeadbeef), }, "cannot mount /sysroot: unique error 3735928559 injected by the test suite", true}, - {"absolute", &AbsoluteError{"etc/mtab"}, + {"absolute", &check.AbsoluteError{Pathname: "etc/mtab"}, `path "etc/mtab" is not absolute`, true}, {"repeat", OpRepeatError("autoetc"), diff --git a/container/init_test.go b/container/init_test.go index 57cdd44..de700db 100644 --- a/container/init_test.go +++ b/container/init_test.go @@ -7,6 +7,7 @@ import ( "time" "hakurei.app/container/bits" + "hakurei.app/container/check" "hakurei.app/container/seccomp" "hakurei.app/container/stub" ) @@ -58,9 +59,9 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, @@ -82,9 +83,9 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, @@ -110,9 +111,9 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, @@ -139,9 +140,9 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, @@ -169,9 +170,9 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, @@ -200,9 +201,9 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, @@ -232,9 +233,9 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, @@ -266,9 +267,9 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, @@ -302,9 +303,9 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, @@ -340,9 +341,9 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, @@ -378,16 +379,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -417,16 +418,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -456,16 +457,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -496,16 +497,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -537,16 +538,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -579,16 +580,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -622,16 +623,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -666,16 +667,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -711,16 +712,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -757,16 +758,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -798,7 +799,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, stub.UniqueError(44)), call("fatalf", stub.ExpectArgs{"cannot apply op at index %d: %v", []any{1, stub.UniqueError(44)}}, nil, nil), @@ -812,16 +813,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -853,7 +854,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, &MountError{"proc", "/sysroot/proc", "proc", uintptr(0xe), "", syscall.ENOTRECOVERABLE}), call("fatal", stub.ExpectArgs{[]any{"cannot mount proc on /sysroot/proc: state not recoverable"}}, nil, nil), @@ -867,16 +868,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -908,7 +909,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -923,16 +924,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -964,7 +965,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -980,16 +981,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1021,7 +1022,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1039,16 +1040,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1080,7 +1081,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1099,16 +1100,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1140,7 +1141,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1160,16 +1161,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1201,7 +1202,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1222,16 +1223,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1263,7 +1264,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1285,16 +1286,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1326,7 +1327,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1349,16 +1350,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1390,7 +1391,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1414,16 +1415,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1455,7 +1456,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1480,16 +1481,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1521,7 +1522,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1554,16 +1555,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1595,7 +1596,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1661,16 +1662,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1702,7 +1703,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1769,16 +1770,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -1810,7 +1811,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1880,15 +1881,15 @@ func TestInitEntrypoint(t *testing.T) { call("setPtracer", stub.ExpectArgs{uintptr(0)}, 0, stub.UniqueError(14)), call("verbosef", stub.ExpectArgs{"cannot enable ptrace protection via Yama LSM: %v", []any{stub.UniqueError(14)}}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei/nonexistent"), - Path: MustAbs("/run/current-system/sw/bin/bash"), + Dir: check.MustAbs("/.hakurei/nonexistent"), + Path: check.MustAbs("/run/current-system/sw/bin/bash"), Args: []string{"bash", "-c", "false"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 24, Gid: 1 << 47, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompDisable: true, ParentPerm: 0750, @@ -1919,7 +1920,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0750)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -1980,7 +1981,7 @@ func TestInitEntrypoint(t *testing.T) { call("newFile", stub.ExpectArgs{uintptr(0x3a), "extra file 0"}, (*os.File)(nil), nil), call("newFile", stub.ExpectArgs{uintptr(0x3b), "extra file 1"}, (*os.File)(nil), nil), call("umask", stub.ExpectArgs{022}, 0, nil), - call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), + call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{check.MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), call("start", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent"}, nil, stub.UniqueError(12)), call("fatalf", stub.ExpectArgs{"%v", []any{stub.UniqueError(12)}}, nil, nil), }, @@ -1994,15 +1995,15 @@ func TestInitEntrypoint(t *testing.T) { call("setPtracer", stub.ExpectArgs{uintptr(0)}, 0, stub.UniqueError(11)), call("verbosef", stub.ExpectArgs{"cannot enable ptrace protection via Yama LSM: %v", []any{stub.UniqueError(11)}}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei/nonexistent"), - Path: MustAbs("/run/current-system/sw/bin/bash"), + Dir: check.MustAbs("/.hakurei/nonexistent"), + Path: check.MustAbs("/run/current-system/sw/bin/bash"), Args: []string{"bash", "-c", "false"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Nanosecond, Uid: 1 << 24, Gid: 1 << 47, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompDisable: true, ParentPerm: 0750, @@ -2033,7 +2034,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0750)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -2058,7 +2059,7 @@ func TestInitEntrypoint(t *testing.T) { call("newFile", stub.ExpectArgs{uintptr(0x3a), "extra file 0"}, (*os.File)(nil), nil), call("newFile", stub.ExpectArgs{uintptr(0x3b), "extra file 1"}, (*os.File)(nil), nil), call("umask", stub.ExpectArgs{022}, 0, nil), - call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), + call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{check.MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), call("start", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent"}, &os.Process{Pid: 0xbad}, nil), call("suspend", stub.ExpectArgs{}, true, nil), call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(10)}}, nil, nil), @@ -2094,15 +2095,15 @@ func TestInitEntrypoint(t *testing.T) { call("setPtracer", stub.ExpectArgs{uintptr(0)}, 0, stub.UniqueError(8)), call("verbosef", stub.ExpectArgs{"cannot enable ptrace protection via Yama LSM: %v", []any{stub.UniqueError(8)}}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei/nonexistent"), - Path: MustAbs("/run/current-system/sw/bin/bash"), + Dir: check.MustAbs("/.hakurei/nonexistent"), + Path: check.MustAbs("/run/current-system/sw/bin/bash"), Args: []string{"bash", "-c", "false"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Nanosecond, Uid: 1 << 24, Gid: 1 << 47, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompDisable: true, ParentPerm: 0750, @@ -2133,7 +2134,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0750)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -2158,7 +2159,7 @@ func TestInitEntrypoint(t *testing.T) { call("newFile", stub.ExpectArgs{uintptr(0x3a), "extra file 0"}, (*os.File)(nil), nil), call("newFile", stub.ExpectArgs{uintptr(0x3b), "extra file 1"}, (*os.File)(nil), nil), call("umask", stub.ExpectArgs{022}, 0, nil), - call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), + call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{check.MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), call("start", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent"}, &os.Process{Pid: 0xbad}, nil), call("suspend", stub.ExpectArgs{}, true, nil), call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(7)}}, nil, nil), @@ -2185,15 +2186,15 @@ func TestInitEntrypoint(t *testing.T) { call("setPtracer", stub.ExpectArgs{uintptr(0)}, 0, stub.UniqueError(6)), call("verbosef", stub.ExpectArgs{"cannot enable ptrace protection via Yama LSM: %v", []any{stub.UniqueError(6)}}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei/nonexistent"), - Path: MustAbs("/run/current-system/sw/bin/bash"), + Dir: check.MustAbs("/.hakurei/nonexistent"), + Path: check.MustAbs("/run/current-system/sw/bin/bash"), Args: []string{"bash", "-c", "false"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Nanosecond, Uid: 1 << 24, Gid: 1 << 47, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompDisable: true, ParentPerm: 0750, @@ -2224,7 +2225,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0750)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -2249,7 +2250,7 @@ func TestInitEntrypoint(t *testing.T) { call("newFile", stub.ExpectArgs{uintptr(0x3a), "extra file 0"}, (*os.File)(nil), nil), call("newFile", stub.ExpectArgs{uintptr(0x3b), "extra file 1"}, (*os.File)(nil), nil), call("umask", stub.ExpectArgs{022}, 0, nil), - call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), + call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{check.MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), call("start", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent"}, &os.Process{Pid: 0xbad}, nil), call("suspend", stub.ExpectArgs{}, true, nil), call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(5)}}, nil, nil), @@ -2278,15 +2279,15 @@ func TestInitEntrypoint(t *testing.T) { call("setPtracer", stub.ExpectArgs{uintptr(0)}, 0, stub.UniqueError(4)), call("verbosef", stub.ExpectArgs{"cannot enable ptrace protection via Yama LSM: %v", []any{stub.UniqueError(4)}}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei/nonexistent"), - Path: MustAbs("/run/current-system/sw/bin/bash"), + Dir: check.MustAbs("/.hakurei/nonexistent"), + Path: check.MustAbs("/run/current-system/sw/bin/bash"), Args: []string{"bash", "-c", "false"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 24, Gid: 1 << 47, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompDisable: true, ParentPerm: 0750, @@ -2317,7 +2318,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0750)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -2342,7 +2343,7 @@ func TestInitEntrypoint(t *testing.T) { call("newFile", stub.ExpectArgs{uintptr(0x3a), "extra file 0"}, (*os.File)(nil), nil), call("newFile", stub.ExpectArgs{uintptr(0x3b), "extra file 1"}, (*os.File)(nil), nil), call("umask", stub.ExpectArgs{022}, 0, nil), - call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), + call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{check.MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), call("start", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent"}, &os.Process{Pid: 0xbad}, nil), call("suspend", stub.ExpectArgs{}, true, nil), call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(3)}}, nil, nil), @@ -2378,15 +2379,15 @@ func TestInitEntrypoint(t *testing.T) { call("setPtracer", stub.ExpectArgs{uintptr(0)}, 0, stub.UniqueError(2)), call("verbosef", stub.ExpectArgs{"cannot enable ptrace protection via Yama LSM: %v", []any{stub.UniqueError(2)}}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei/nonexistent"), - Path: MustAbs("/run/current-system/sw/bin/bash"), + Dir: check.MustAbs("/.hakurei/nonexistent"), + Path: check.MustAbs("/run/current-system/sw/bin/bash"), Args: []string{"bash", "-c", "false"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 24, Gid: 1 << 47, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompDisable: true, ParentPerm: 0750, @@ -2417,7 +2418,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0750)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -2478,7 +2479,7 @@ func TestInitEntrypoint(t *testing.T) { call("newFile", stub.ExpectArgs{uintptr(0x3a), "extra file 0"}, (*os.File)(nil), nil), call("newFile", stub.ExpectArgs{uintptr(0x3b), "extra file 1"}, (*os.File)(nil), nil), call("umask", stub.ExpectArgs{022}, 0, nil), - call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), + call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{check.MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil), call("start", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent"}, &os.Process{Pid: 0xbad}, nil), call("suspend", stub.ExpectArgs{}, true, nil), call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(1)}}, nil, nil), @@ -2513,16 +2514,16 @@ func TestInitEntrypoint(t *testing.T) { call("getpid", stub.ExpectArgs{}, 1, nil), call("setPtracer", stub.ExpectArgs{uintptr(0)}, nil, nil), call("receive", stub.ExpectArgs{"HAKUREI_SETUP", new(initParams), new(uintptr), &initParams{Params{ - Dir: MustAbs("/.hakurei"), + Dir: check.MustAbs("/.hakurei"), Env: []string{"DISPLAY=:0"}, - Path: MustAbs("/bin/zsh"), + Path: check.MustAbs("/bin/zsh"), Args: []string{"zsh", "-c", "exec vim"}, ForwardCancel: true, AdoptWaitDelay: 5 * time.Second, Uid: 1 << 32, Gid: 1 << 31, Hostname: "hakurei-check", - Ops: new(Ops).Bind(MustAbs("/"), MustAbs("/"), BindDevice).Proc(MustAbs("/proc/")), + Ops: new(Ops).Bind(check.MustAbs("/"), check.MustAbs("/"), BindDevice).Proc(check.MustAbs("/proc/")), SeccompRules: make([]seccomp.NativeRule, 0), SeccompPresets: bits.PresetStrict, RetainSession: true, @@ -2554,7 +2555,7 @@ func TestInitEntrypoint(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0700)}, nil, nil), call("verbosef", stub.ExpectArgs{"mounting %q flags %#x", []any{"/sysroot", uintptr(0x4001)}}, nil, nil), call("bindMount", stub.ExpectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil), - call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil), + call("verbosef", stub.ExpectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: check.MustAbs("/proc/")}}}, nil, nil), call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), /* end apply */ @@ -2618,7 +2619,7 @@ func TestInitEntrypoint(t *testing.T) { call("newFile", stub.ExpectArgs{uintptr(11), "extra file 1"}, (*os.File)(nil), nil), call("newFile", stub.ExpectArgs{uintptr(12), "extra file 2"}, (*os.File)(nil), nil), call("umask", stub.ExpectArgs{022}, 0, nil), - call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/bin/zsh")}}, nil, nil), + call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{check.MustAbs("/bin/zsh")}}, nil, nil), call("start", stub.ExpectArgs{"/bin/zsh", []string{"zsh", "-c", "exec vim"}, []string{"DISPLAY=:0"}, "/.hakurei"}, &os.Process{Pid: 0xcafe}, nil), call("suspend", stub.ExpectArgs{}, true, nil), call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(0)}}, nil, nil), diff --git a/container/initbind.go b/container/initbind.go index 43c8310..0cb2e2f 100644 --- a/container/initbind.go +++ b/container/initbind.go @@ -5,12 +5,14 @@ import ( "fmt" "os" "syscall" + + "hakurei.app/container/check" ) func init() { gob.Register(new(BindMountOp)) } // Bind appends an [Op] that bind mounts host path [BindMountOp.Source] on container path [BindMountOp.Target]. -func (f *Ops) Bind(source, target *Absolute, flags int) *Ops { +func (f *Ops) Bind(source, target *check.Absolute, flags int) *Ops { *f = append(*f, &BindMountOp{nil, source, target, flags}) return f } @@ -18,7 +20,7 @@ func (f *Ops) Bind(source, target *Absolute, flags int) *Ops { // BindMountOp bind mounts host path Source on container path Target. // Note that Flags uses bits declared in this package and should not be set with constants in [syscall]. type BindMountOp struct { - sourceFinal, Source, Target *Absolute + sourceFinal, Source, Target *check.Absolute Flags int } @@ -54,7 +56,7 @@ func (b *BindMountOp) early(_ *setupState, k syscallDispatcher) error { } return err } else { - b.sourceFinal, err = NewAbs(pathname) + b.sourceFinal, err = check.NewAbs(pathname) return err } } diff --git a/container/initbind_test.go b/container/initbind_test.go index 5be91ed..5e0c37e 100644 --- a/container/initbind_test.go +++ b/container/initbind_test.go @@ -6,29 +6,30 @@ import ( "syscall" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" ) func TestBindMountOp(t *testing.T) { checkOpBehaviour(t, []opBehaviourTestCase{ {"ENOENT not optional", new(Params), &BindMountOp{ - Source: MustAbs("/bin/"), - Target: MustAbs("/bin/"), + Source: check.MustAbs("/bin/"), + Target: check.MustAbs("/bin/"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "", syscall.ENOENT), }, syscall.ENOENT, nil, nil}, {"skip optional", new(Params), &BindMountOp{ - Source: MustAbs("/bin/"), - Target: MustAbs("/bin/"), + Source: check.MustAbs("/bin/"), + Target: check.MustAbs("/bin/"), Flags: BindOptional, }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "", syscall.ENOENT), }, nil, nil, nil}, {"success optional", new(Params), &BindMountOp{ - Source: MustAbs("/bin/"), - Target: MustAbs("/bin/"), + Source: check.MustAbs("/bin/"), + Target: check.MustAbs("/bin/"), Flags: BindOptional, }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", nil), @@ -40,8 +41,8 @@ func TestBindMountOp(t *testing.T) { }, nil}, {"ensureFile device", new(Params), &BindMountOp{ - Source: MustAbs("/dev/null"), - Target: MustAbs("/dev/null"), + Source: check.MustAbs("/dev/null"), + Target: check.MustAbs("/dev/null"), Flags: BindWritable | BindDevice, }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil), @@ -51,16 +52,16 @@ func TestBindMountOp(t *testing.T) { }, stub.UniqueError(5)}, {"mkdirAll ensure", new(Params), &BindMountOp{ - Source: MustAbs("/bin/"), - Target: MustAbs("/bin/"), + Source: check.MustAbs("/bin/"), + Target: check.MustAbs("/bin/"), Flags: BindEnsure, }, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/bin/", os.FileMode(0700)}, nil, stub.UniqueError(4)), }, stub.UniqueError(4), nil, nil}, {"success ensure", new(Params), &BindMountOp{ - Source: MustAbs("/bin/"), - Target: MustAbs("/usr/bin/"), + Source: check.MustAbs("/bin/"), + Target: check.MustAbs("/usr/bin/"), Flags: BindEnsure, }, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/bin/", os.FileMode(0700)}, nil, nil), @@ -73,8 +74,8 @@ func TestBindMountOp(t *testing.T) { }, nil}, {"success device ro", new(Params), &BindMountOp{ - Source: MustAbs("/dev/null"), - Target: MustAbs("/dev/null"), + Source: check.MustAbs("/dev/null"), + Target: check.MustAbs("/dev/null"), Flags: BindDevice, }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil), @@ -86,8 +87,8 @@ func TestBindMountOp(t *testing.T) { }, nil}, {"success device", new(Params), &BindMountOp{ - Source: MustAbs("/dev/null"), - Target: MustAbs("/dev/null"), + Source: check.MustAbs("/dev/null"), + Target: check.MustAbs("/dev/null"), Flags: BindWritable | BindDevice, }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil), @@ -99,15 +100,15 @@ func TestBindMountOp(t *testing.T) { }, nil}, {"evalSymlinks", new(Params), &BindMountOp{ - Source: MustAbs("/bin/"), - Target: MustAbs("/bin/"), + Source: check.MustAbs("/bin/"), + Target: check.MustAbs("/bin/"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", stub.UniqueError(3)), }, stub.UniqueError(3), nil, nil}, {"stat", new(Params), &BindMountOp{ - Source: MustAbs("/bin/"), - Target: MustAbs("/bin/"), + Source: check.MustAbs("/bin/"), + Target: check.MustAbs("/bin/"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", nil), }, nil, []stub.Call{ @@ -115,8 +116,8 @@ func TestBindMountOp(t *testing.T) { }, stub.UniqueError(2)}, {"mkdirAll", new(Params), &BindMountOp{ - Source: MustAbs("/bin/"), - Target: MustAbs("/bin/"), + Source: check.MustAbs("/bin/"), + Target: check.MustAbs("/bin/"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", nil), }, nil, []stub.Call{ @@ -125,8 +126,8 @@ func TestBindMountOp(t *testing.T) { }, stub.UniqueError(1)}, {"bindMount", new(Params), &BindMountOp{ - Source: MustAbs("/bin/"), - Target: MustAbs("/bin/"), + Source: check.MustAbs("/bin/"), + Target: check.MustAbs("/bin/"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", nil), }, nil, []stub.Call{ @@ -137,8 +138,8 @@ func TestBindMountOp(t *testing.T) { }, stub.UniqueError(0)}, {"success eval equals", new(Params), &BindMountOp{ - Source: MustAbs("/bin/"), - Target: MustAbs("/bin/"), + Source: check.MustAbs("/bin/"), + Target: check.MustAbs("/bin/"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/bin", nil), }, nil, []stub.Call{ @@ -149,8 +150,8 @@ func TestBindMountOp(t *testing.T) { }, nil}, {"success", new(Params), &BindMountOp{ - Source: MustAbs("/bin/"), - Target: MustAbs("/bin/"), + Source: check.MustAbs("/bin/"), + Target: check.MustAbs("/bin/"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", nil), }, nil, []stub.Call{ @@ -173,21 +174,21 @@ func TestBindMountOp(t *testing.T) { checkOpsValid(t, []opValidTestCase{ {"nil", (*BindMountOp)(nil), false}, {"zero", new(BindMountOp), false}, - {"nil source", &BindMountOp{Target: MustAbs("/")}, false}, - {"nil target", &BindMountOp{Source: MustAbs("/")}, false}, - {"flag optional ensure", &BindMountOp{Source: MustAbs("/"), Target: MustAbs("/"), Flags: BindOptional | BindEnsure}, false}, - {"valid", &BindMountOp{Source: MustAbs("/"), Target: MustAbs("/")}, true}, + {"nil source", &BindMountOp{Target: check.MustAbs("/")}, false}, + {"nil target", &BindMountOp{Source: check.MustAbs("/")}, false}, + {"flag optional ensure", &BindMountOp{Source: check.MustAbs("/"), Target: check.MustAbs("/"), Flags: BindOptional | BindEnsure}, false}, + {"valid", &BindMountOp{Source: check.MustAbs("/"), Target: check.MustAbs("/")}, true}, }) checkOpsBuilder(t, []opsBuilderTestCase{ {"autoetc", new(Ops).Bind( - MustAbs("/etc/"), - MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + check.MustAbs("/etc/"), + check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), 0, ), Ops{ &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), }, }}, }) @@ -196,45 +197,45 @@ func TestBindMountOp(t *testing.T) { {"zero", new(BindMountOp), new(BindMountOp), false}, {"internal ne", &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), }, &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), - sourceFinal: MustAbs("/etc/"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + sourceFinal: check.MustAbs("/etc/"), }, true}, {"flags differs", &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), }, &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), Flags: BindOptional, }, false}, {"source differs", &BindMountOp{ - Source: MustAbs("/.hakurei/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + Source: check.MustAbs("/.hakurei/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), }, &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), }, false}, {"target differs", &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), }, &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/"), }, false}, {"equals", &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), }, &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), }, true}, }) @@ -242,13 +243,13 @@ func TestBindMountOp(t *testing.T) { {"invalid", new(BindMountOp), "mounting", ""}, {"autoetc", &BindMountOp{ - Source: MustAbs("/etc/"), - Target: MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), + Source: check.MustAbs("/etc/"), + Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"), }, "mounting", `"/etc/" on "/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659" flags 0x0`}, {"hostdev", &BindMountOp{ - Source: MustAbs("/dev/"), - Target: MustAbs("/dev/"), + Source: check.MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Flags: BindWritable | BindDevice, }, "mounting", `"/dev/" flags 0x6`}, }) diff --git a/container/initdev.go b/container/initdev.go index 335cac0..e7c4eab 100644 --- a/container/initdev.go +++ b/container/initdev.go @@ -5,19 +5,21 @@ import ( "fmt" "path" . "syscall" + + "hakurei.app/container/check" ) func init() { gob.Register(new(MountDevOp)) } // Dev appends an [Op] that mounts a subset of host /dev. -func (f *Ops) Dev(target *Absolute, mqueue bool) *Ops { +func (f *Ops) Dev(target *check.Absolute, mqueue bool) *Ops { *f = append(*f, &MountDevOp{target, mqueue, false}) return f } // DevWritable appends an [Op] that mounts a writable subset of host /dev. // There is usually no good reason to write to /dev, so this should always be followed by a [RemountOp]. -func (f *Ops) DevWritable(target *Absolute, mqueue bool) *Ops { +func (f *Ops) DevWritable(target *check.Absolute, mqueue bool) *Ops { *f = append(*f, &MountDevOp{target, mqueue, true}) return f } @@ -26,7 +28,7 @@ func (f *Ops) DevWritable(target *Absolute, mqueue bool) *Ops { // If Mqueue is true, a private instance of [FstypeMqueue] is mounted. // If Write is true, the resulting mount point is left writable. type MountDevOp struct { - Target *Absolute + Target *check.Absolute Mqueue bool Write bool } diff --git a/container/initdev_test.go b/container/initdev_test.go index 5613d5d..4081dd2 100644 --- a/container/initdev_test.go +++ b/container/initdev_test.go @@ -4,20 +4,21 @@ import ( "os" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" ) func TestMountDevOp(t *testing.T) { checkOpBehaviour(t, []opBehaviourTestCase{ {"mountTmpfs", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, stub.UniqueError(27)), }, stub.UniqueError(27)}, {"ensureFile null", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -25,7 +26,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(26)}, {"bindMount null", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -34,7 +35,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(25)}, {"ensureFile zero", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -44,7 +45,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(24)}, {"bindMount zero", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -55,7 +56,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(23)}, {"ensureFile full", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -67,7 +68,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(22)}, {"bindMount full", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -80,7 +81,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(21)}, {"ensureFile random", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -94,7 +95,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(20)}, {"bindMount random", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -109,7 +110,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(19)}, {"ensureFile urandom", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -125,7 +126,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(18)}, {"bindMount urandom", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -142,7 +143,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(17)}, {"ensureFile tty", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -160,7 +161,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(16)}, {"bindMount tty", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -179,7 +180,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(15)}, {"symlink stdin", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -199,7 +200,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(14)}, {"symlink stdout", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -220,7 +221,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(13)}, {"symlink stderr", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -242,7 +243,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(12)}, {"symlink fd", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -265,7 +266,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(11)}, {"symlink kcore", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -289,7 +290,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(10)}, {"symlink ptmx", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -314,7 +315,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(9)}, {"mkdir shm", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -340,7 +341,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(8)}, {"mkdir devpts", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -367,7 +368,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(7)}, {"mount devpts", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -395,7 +396,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(6)}, {"ensureFile stdout", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -425,7 +426,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(5)}, {"readlink stdout", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -456,7 +457,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(4)}, {"bindMount stdout", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -488,7 +489,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(3)}, {"mkdir mqueue", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -521,7 +522,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(2)}, {"mount mqueue", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -555,7 +556,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(1)}, {"success no session", &Params{ParentPerm: 0755}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, Write: true, }, nil, nil, []stub.Call{ @@ -586,7 +587,7 @@ func TestMountDevOp(t *testing.T) { }, nil}, {"success no tty", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, Write: true, }, nil, nil, []stub.Call{ @@ -618,7 +619,7 @@ func TestMountDevOp(t *testing.T) { }, nil}, {"remount", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), call("ensureFile", stub.ExpectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil), @@ -650,7 +651,7 @@ func TestMountDevOp(t *testing.T) { }, stub.UniqueError(0)}, {"success no mqueue", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), call("ensureFile", stub.ExpectArgs{"/sysroot/dev/null", os.FileMode(0444), os.FileMode(0750)}, nil, nil), @@ -683,7 +684,7 @@ func TestMountDevOp(t *testing.T) { }, nil}, {"success rw", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, Write: true, }, nil, nil, []stub.Call{ @@ -718,7 +719,7 @@ func TestMountDevOp(t *testing.T) { }, nil}, {"success", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, nil, nil, []stub.Call{ call("mountTmpfs", stub.ExpectArgs{"devtmpfs", "/sysroot/dev", uintptr(0x6), 0, os.FileMode(0750)}, nil, nil), @@ -757,20 +758,20 @@ func TestMountDevOp(t *testing.T) { checkOpsValid(t, []opValidTestCase{ {"nil", (*MountDevOp)(nil), false}, {"zero", new(MountDevOp), false}, - {"valid", &MountDevOp{Target: MustAbs("/dev/")}, true}, + {"valid", &MountDevOp{Target: check.MustAbs("/dev/")}, true}, }) checkOpsBuilder(t, []opsBuilderTestCase{ - {"dev", new(Ops).Dev(MustAbs("/dev/"), true), Ops{ + {"dev", new(Ops).Dev(check.MustAbs("/dev/"), true), Ops{ &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, }}, - {"dev writable", new(Ops).DevWritable(MustAbs("/.hakurei/dev/"), false), Ops{ + {"dev writable", new(Ops).DevWritable(check.MustAbs("/.hakurei/dev/"), false), Ops{ &MountDevOp{ - Target: MustAbs("/.hakurei/dev/"), + Target: check.MustAbs("/.hakurei/dev/"), Write: true, }, }}, @@ -780,46 +781,46 @@ func TestMountDevOp(t *testing.T) { {"zero", new(MountDevOp), new(MountDevOp), false}, {"write differs", &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, Write: true, }, false}, {"mqueue differs", &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), }, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, false}, {"target differs", &MountDevOp{ - Target: MustAbs("/"), + Target: check.MustAbs("/"), Mqueue: true, }, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, false}, {"equals", &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, true}, }) checkOpMeta(t, []opMetaTestCase{ {"mqueue", &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Mqueue: true, }, "mounting", `dev on "/dev/" with mqueue`}, {"dev", &MountDevOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), }, "mounting", `dev on "/dev/"`}, }) } diff --git a/container/initmkdir.go b/container/initmkdir.go index 375c0e0..218d634 100644 --- a/container/initmkdir.go +++ b/container/initmkdir.go @@ -4,19 +4,21 @@ import ( "encoding/gob" "fmt" "os" + + "hakurei.app/container/check" ) func init() { gob.Register(new(MkdirOp)) } // Mkdir appends an [Op] that creates a directory in the container filesystem. -func (f *Ops) Mkdir(name *Absolute, perm os.FileMode) *Ops { +func (f *Ops) Mkdir(name *check.Absolute, perm os.FileMode) *Ops { *f = append(*f, &MkdirOp{name, perm}) return f } // MkdirOp creates a directory at container Path with permission bits set to Perm. type MkdirOp struct { - Path *Absolute + Path *check.Absolute Perm os.FileMode } diff --git a/container/initmkdir_test.go b/container/initmkdir_test.go index 0d3f302..31f3fb8 100644 --- a/container/initmkdir_test.go +++ b/container/initmkdir_test.go @@ -4,13 +4,14 @@ import ( "os" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" ) func TestMkdirOp(t *testing.T) { checkOpBehaviour(t, []opBehaviourTestCase{ {"success", new(Params), &MkdirOp{ - Path: MustAbs("/.hakurei"), + Path: check.MustAbs("/.hakurei"), Perm: 0500, }, nil, nil, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/sysroot/.hakurei", os.FileMode(0500)}, nil, nil), @@ -20,25 +21,25 @@ func TestMkdirOp(t *testing.T) { checkOpsValid(t, []opValidTestCase{ {"nil", (*MkdirOp)(nil), false}, {"zero", new(MkdirOp), false}, - {"valid", &MkdirOp{Path: MustAbs("/.hakurei")}, true}, + {"valid", &MkdirOp{Path: check.MustAbs("/.hakurei")}, true}, }) checkOpsBuilder(t, []opsBuilderTestCase{ - {"etc", new(Ops).Mkdir(MustAbs("/etc/"), 0), Ops{ - &MkdirOp{Path: MustAbs("/etc/")}, + {"etc", new(Ops).Mkdir(check.MustAbs("/etc/"), 0), Ops{ + &MkdirOp{Path: check.MustAbs("/etc/")}, }}, }) checkOpIs(t, []opIsTestCase{ {"zero", new(MkdirOp), new(MkdirOp), false}, - {"path differs", &MkdirOp{Path: MustAbs("/"), Perm: 0755}, &MkdirOp{Path: MustAbs("/etc/"), Perm: 0755}, false}, - {"perm differs", &MkdirOp{Path: MustAbs("/")}, &MkdirOp{Path: MustAbs("/"), Perm: 0755}, false}, - {"equals", &MkdirOp{Path: MustAbs("/")}, &MkdirOp{Path: MustAbs("/")}, true}, + {"path differs", &MkdirOp{Path: check.MustAbs("/"), Perm: 0755}, &MkdirOp{Path: check.MustAbs("/etc/"), Perm: 0755}, false}, + {"perm differs", &MkdirOp{Path: check.MustAbs("/")}, &MkdirOp{Path: check.MustAbs("/"), Perm: 0755}, false}, + {"equals", &MkdirOp{Path: check.MustAbs("/")}, &MkdirOp{Path: check.MustAbs("/")}, true}, }) checkOpMeta(t, []opMetaTestCase{ {"etc", &MkdirOp{ - Path: MustAbs("/etc/"), + Path: check.MustAbs("/etc/"), }, "creating", `directory "/etc/" perm ----------`}, }) } diff --git a/container/initoverlay.go b/container/initoverlay.go index a123928..74d925a 100644 --- a/container/initoverlay.go +++ b/container/initoverlay.go @@ -5,6 +5,8 @@ import ( "fmt" "slices" "strings" + + "hakurei.app/container/check" ) const ( @@ -52,7 +54,7 @@ func (e *OverlayArgumentError) Error() string { } // Overlay appends an [Op] that mounts the overlay pseudo filesystem on [MountOverlayOp.Target]. -func (f *Ops) Overlay(target, state, work *Absolute, layers ...*Absolute) *Ops { +func (f *Ops) Overlay(target, state, work *check.Absolute, layers ...*check.Absolute) *Ops { *f = append(*f, &MountOverlayOp{ Target: target, Lower: layers, @@ -64,21 +66,21 @@ func (f *Ops) Overlay(target, state, work *Absolute, layers ...*Absolute) *Ops { // OverlayEphemeral appends an [Op] that mounts the overlay pseudo filesystem on [MountOverlayOp.Target] // with an ephemeral upperdir and workdir. -func (f *Ops) OverlayEphemeral(target *Absolute, layers ...*Absolute) *Ops { +func (f *Ops) OverlayEphemeral(target *check.Absolute, layers ...*check.Absolute) *Ops { return f.Overlay(target, AbsFHSRoot, nil, layers...) } // OverlayReadonly appends an [Op] that mounts the overlay pseudo filesystem readonly on [MountOverlayOp.Target] -func (f *Ops) OverlayReadonly(target *Absolute, layers ...*Absolute) *Ops { +func (f *Ops) OverlayReadonly(target *check.Absolute, layers ...*check.Absolute) *Ops { return f.Overlay(target, nil, nil, layers...) } // MountOverlayOp mounts [FstypeOverlay] on container path Target. type MountOverlayOp struct { - Target *Absolute + Target *check.Absolute // Any filesystem, does not need to be on a writable filesystem. - Lower []*Absolute + Lower []*check.Absolute // formatted for [OptionOverlayLowerdir], resolved, prefixed and escaped during early lower []string // The upperdir is normally on a writable filesystem. @@ -87,11 +89,11 @@ type MountOverlayOp struct { // an ephemeral upperdir and workdir will be set up. // // If both Work and Upper are nil, upperdir and workdir is omitted and the overlay is mounted readonly. - Upper *Absolute + Upper *check.Absolute // formatted for [OptionOverlayUpperdir], resolved, prefixed and escaped during early upper string // The workdir needs to be an empty directory on the same filesystem as upperdir. - Work *Absolute + Work *check.Absolute // formatted for [OptionOverlayWorkdir], resolved, prefixed and escaped during early work string @@ -206,7 +208,7 @@ func (o *MountOverlayOp) Is(op Op) bool { vo, ok := op.(*MountOverlayOp) return ok && o.Valid() && vo.Valid() && o.Target.Is(vo.Target) && - slices.EqualFunc(o.Lower, vo.Lower, func(a *Absolute, v *Absolute) bool { return a.Is(v) }) && + slices.EqualFunc(o.Lower, vo.Lower, func(a, v *check.Absolute) bool { return a.Is(v) }) && o.Upper.Is(vo.Upper) && o.Work.Is(vo.Work) } func (*MountOverlayOp) prefix() (string, bool) { return "mounting", true } diff --git a/container/initoverlay_test.go b/container/initoverlay_test.go index d44aa28..ad07ef9 100644 --- a/container/initoverlay_test.go +++ b/container/initoverlay_test.go @@ -5,6 +5,7 @@ import ( "os" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" ) @@ -38,21 +39,21 @@ func TestMountOverlayOp(t *testing.T) { checkOpBehaviour(t, []opBehaviourTestCase{ {"mkdirTemp invalid ephemeral", &Params{ParentPerm: 0705}, &MountOverlayOp{ - Target: MustAbs("/"), - Lower: []*Absolute{ - MustAbs("/var/lib/planterette/base/debian:f92c9052"), - MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"), + Target: check.MustAbs("/"), + Lower: []*check.Absolute{ + check.MustAbs("/var/lib/planterette/base/debian:f92c9052"), + check.MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"), }, - Upper: MustAbs("/proc/"), + Upper: check.MustAbs("/proc/"), }, nil, &OverlayArgumentError{OverlayEphemeralUnexpectedUpper, "/proc/"}, nil, nil}, {"mkdirTemp upper ephemeral", &Params{ParentPerm: 0705}, &MountOverlayOp{ - Target: MustAbs("/"), - Lower: []*Absolute{ - MustAbs("/var/lib/planterette/base/debian:f92c9052"), - MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"), + Target: check.MustAbs("/"), + Lower: []*check.Absolute{ + check.MustAbs("/var/lib/planterette/base/debian:f92c9052"), + check.MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"), }, - Upper: MustAbs("/"), + Upper: check.MustAbs("/"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/var/lib/planterette/base/debian:f92c9052"}, "/var/lib/planterette/base/debian:f92c9052", nil), call("evalSymlinks", stub.ExpectArgs{"/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"}, "/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052", nil), @@ -62,12 +63,12 @@ func TestMountOverlayOp(t *testing.T) { }, stub.UniqueError(6)}, {"mkdirTemp work ephemeral", &Params{ParentPerm: 0705}, &MountOverlayOp{ - Target: MustAbs("/"), - Lower: []*Absolute{ - MustAbs("/var/lib/planterette/base/debian:f92c9052"), - MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"), + Target: check.MustAbs("/"), + Lower: []*check.Absolute{ + check.MustAbs("/var/lib/planterette/base/debian:f92c9052"), + check.MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"), }, - Upper: MustAbs("/"), + Upper: check.MustAbs("/"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/var/lib/planterette/base/debian:f92c9052"}, "/var/lib/planterette/base/debian:f92c9052", nil), call("evalSymlinks", stub.ExpectArgs{"/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"}, "/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052", nil), @@ -78,12 +79,12 @@ func TestMountOverlayOp(t *testing.T) { }, stub.UniqueError(5)}, {"success ephemeral", &Params{ParentPerm: 0705}, &MountOverlayOp{ - Target: MustAbs("/"), - Lower: []*Absolute{ - MustAbs("/var/lib/planterette/base/debian:f92c9052"), - MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"), + Target: check.MustAbs("/"), + Lower: []*check.Absolute{ + check.MustAbs("/var/lib/planterette/base/debian:f92c9052"), + check.MustAbs("/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"), }, - Upper: MustAbs("/"), + Upper: check.MustAbs("/"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/var/lib/planterette/base/debian:f92c9052"}, "/var/lib/planterette/base/debian:f92c9052", nil), call("evalSymlinks", stub.ExpectArgs{"/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052"}, "/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052", nil), @@ -101,9 +102,9 @@ func TestMountOverlayOp(t *testing.T) { }, nil}, {"short lower ro", &Params{ParentPerm: 0755}, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{ - MustAbs("/mnt-root/nix/.ro-store"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{ + check.MustAbs("/mnt-root/nix/.ro-store"), }, }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/.ro-store", nil), @@ -112,10 +113,10 @@ func TestMountOverlayOp(t *testing.T) { }, &OverlayArgumentError{OverlayReadonlyLower, zeroString}}, {"success ro noPrefix", &Params{ParentPerm: 0755}, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{ - MustAbs("/mnt-root/nix/.ro-store"), - MustAbs("/mnt-root/nix/.ro-store0"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{ + check.MustAbs("/mnt-root/nix/.ro-store"), + check.MustAbs("/mnt-root/nix/.ro-store0"), }, noPrefix: true, }, []stub.Call{ @@ -131,10 +132,10 @@ func TestMountOverlayOp(t *testing.T) { }, nil}, {"success ro", &Params{ParentPerm: 0755}, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{ - MustAbs("/mnt-root/nix/.ro-store"), - MustAbs("/mnt-root/nix/.ro-store0"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{ + check.MustAbs("/mnt-root/nix/.ro-store"), + check.MustAbs("/mnt-root/nix/.ro-store0"), }, }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/.ro-store", nil), @@ -149,9 +150,9 @@ func TestMountOverlayOp(t *testing.T) { }, nil}, {"nil lower", &Params{ParentPerm: 0700}, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil), call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil), @@ -160,29 +161,29 @@ func TestMountOverlayOp(t *testing.T) { }, &OverlayArgumentError{OverlayEmptyLower, zeroString}}, {"evalSymlinks upper", &Params{ParentPerm: 0700}, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", stub.UniqueError(4)), }, stub.UniqueError(4), nil, nil}, {"evalSymlinks work", &Params{ParentPerm: 0700}, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil), call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", stub.UniqueError(3)), }, stub.UniqueError(3), nil, nil}, {"evalSymlinks lower", &Params{ParentPerm: 0700}, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil), call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil), @@ -190,10 +191,10 @@ func TestMountOverlayOp(t *testing.T) { }, stub.UniqueError(2), nil, nil}, {"mkdirAll", &Params{ParentPerm: 0700}, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil), call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil), @@ -203,10 +204,10 @@ func TestMountOverlayOp(t *testing.T) { }, stub.UniqueError(1)}, {"mount", &Params{ParentPerm: 0700}, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil), call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil), @@ -217,10 +218,10 @@ func TestMountOverlayOp(t *testing.T) { }, stub.UniqueError(0)}, {"success single layer", &Params{ParentPerm: 0700}, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil), call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil), @@ -235,16 +236,16 @@ func TestMountOverlayOp(t *testing.T) { }, nil}, {"success", &Params{ParentPerm: 0700}, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{ - MustAbs("/mnt-root/nix/.ro-store"), - MustAbs("/mnt-root/nix/.ro-store0"), - MustAbs("/mnt-root/nix/.ro-store1"), - MustAbs("/mnt-root/nix/.ro-store2"), - MustAbs("/mnt-root/nix/.ro-store3"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{ + check.MustAbs("/mnt-root/nix/.ro-store"), + check.MustAbs("/mnt-root/nix/.ro-store0"), + check.MustAbs("/mnt-root/nix/.ro-store1"), + check.MustAbs("/mnt-root/nix/.ro-store2"), + check.MustAbs("/mnt-root/nix/.ro-store3"), }, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, []stub.Call{ call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/upper"}, "/mnt-root/nix/.rw-store/.upper", nil), call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.rw-store/work"}, "/mnt-root/nix/.rw-store/.work", nil), @@ -272,7 +273,7 @@ func TestMountOverlayOp(t *testing.T) { t.Run("nil Upper non-nil Work not ephemeral", func(t *testing.T) { wantErr := OpStateError("overlay") if err := (&MountOverlayOp{ - Work: MustAbs("/"), + Work: check.MustAbs("/"), }).early(nil, nil); !errors.Is(err, wantErr) { t.Errorf("apply: error = %v, want %v", err, wantErr) } @@ -282,39 +283,39 @@ func TestMountOverlayOp(t *testing.T) { checkOpsValid(t, []opValidTestCase{ {"nil", (*MountOverlayOp)(nil), false}, {"zero", new(MountOverlayOp), false}, - {"nil lower", &MountOverlayOp{Target: MustAbs("/"), Lower: []*Absolute{nil}}, false}, - {"ro", &MountOverlayOp{Target: MustAbs("/"), Lower: []*Absolute{MustAbs("/")}}, true}, - {"ro work", &MountOverlayOp{Target: MustAbs("/"), Work: MustAbs("/tmp/")}, false}, - {"rw", &MountOverlayOp{Target: MustAbs("/"), Lower: []*Absolute{MustAbs("/")}, Upper: MustAbs("/"), Work: MustAbs("/")}, true}, + {"nil lower", &MountOverlayOp{Target: check.MustAbs("/"), Lower: []*check.Absolute{nil}}, false}, + {"ro", &MountOverlayOp{Target: check.MustAbs("/"), Lower: []*check.Absolute{check.MustAbs("/")}}, true}, + {"ro work", &MountOverlayOp{Target: check.MustAbs("/"), Work: check.MustAbs("/tmp/")}, false}, + {"rw", &MountOverlayOp{Target: check.MustAbs("/"), Lower: []*check.Absolute{check.MustAbs("/")}, Upper: check.MustAbs("/"), Work: check.MustAbs("/")}, true}, }) checkOpsBuilder(t, []opsBuilderTestCase{ {"full", new(Ops).Overlay( - MustAbs("/nix/store"), - MustAbs("/mnt-root/nix/.rw-store/upper"), - MustAbs("/mnt-root/nix/.rw-store/work"), - MustAbs("/mnt-root/nix/.ro-store"), + check.MustAbs("/nix/store"), + check.MustAbs("/mnt-root/nix/.rw-store/upper"), + check.MustAbs("/mnt-root/nix/.rw-store/work"), + check.MustAbs("/mnt-root/nix/.ro-store"), ), Ops{ &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, }}, - {"ephemeral", new(Ops).OverlayEphemeral(MustAbs("/nix/store"), MustAbs("/mnt-root/nix/.ro-store")), Ops{ + {"ephemeral", new(Ops).OverlayEphemeral(check.MustAbs("/nix/store"), check.MustAbs("/mnt-root/nix/.ro-store")), Ops{ &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/"), }, }}, - {"readonly", new(Ops).OverlayReadonly(MustAbs("/nix/store"), MustAbs("/mnt-root/nix/.ro-store")), Ops{ + {"readonly", new(Ops).OverlayReadonly(check.MustAbs("/nix/store"), check.MustAbs("/mnt-root/nix/.ro-store")), Ops{ &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, }, }}, }) @@ -323,74 +324,74 @@ func TestMountOverlayOp(t *testing.T) { {"zero", new(MountOverlayOp), new(MountOverlayOp), false}, {"differs target", &MountOverlayOp{ - Target: MustAbs("/nix/store/differs"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store/differs"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work")}, false}, + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work")}, false}, {"differs lower", &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store/differs")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store/differs")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work")}, false}, + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work")}, false}, {"differs upper", &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper/differs"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper/differs"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work")}, false}, + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work")}, false}, {"differs work", &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work/differs"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work/differs"), }, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work")}, false}, + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work")}, false}, {"equals ro", &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, }, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}}, true}, + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}}, true}, {"equals", &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work")}, true}, + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work")}, true}, }) checkOpMeta(t, []opMetaTestCase{ {"nix", &MountOverlayOp{ - Target: MustAbs("/nix/store"), - Lower: []*Absolute{MustAbs("/mnt-root/nix/.ro-store")}, - Upper: MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }, "mounting", `overlay on "/nix/store" with 1 layers`}, }) } diff --git a/container/initplace.go b/container/initplace.go index 5975bba..1f41846 100644 --- a/container/initplace.go +++ b/container/initplace.go @@ -4,6 +4,8 @@ import ( "encoding/gob" "fmt" "syscall" + + "hakurei.app/container/check" ) const ( @@ -14,13 +16,13 @@ const ( func init() { gob.Register(new(TmpfileOp)) } // Place appends an [Op] that places a file in container path [TmpfileOp.Path] containing [TmpfileOp.Data]. -func (f *Ops) Place(name *Absolute, data []byte) *Ops { +func (f *Ops) Place(name *check.Absolute, data []byte) *Ops { *f = append(*f, &TmpfileOp{name, data}) return f } // PlaceP is like Place but writes the address of [TmpfileOp.Data] to the pointer dataP points to. -func (f *Ops) PlaceP(name *Absolute, dataP **[]byte) *Ops { +func (f *Ops) PlaceP(name *check.Absolute, dataP **[]byte) *Ops { t := &TmpfileOp{Path: name} *dataP = &t.Data @@ -30,7 +32,7 @@ func (f *Ops) PlaceP(name *Absolute, dataP **[]byte) *Ops { // TmpfileOp places a file on container Path containing Data. type TmpfileOp struct { - Path *Absolute + Path *check.Absolute Data []byte } diff --git a/container/initplace_test.go b/container/initplace_test.go index e8ee695..a330a80 100644 --- a/container/initplace_test.go +++ b/container/initplace_test.go @@ -4,13 +4,14 @@ import ( "os" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" ) func TestTmpfileOp(t *testing.T) { const sampleDataString = `chronos:x:65534:65534:Hakurei:/var/empty:/bin/zsh` var ( - samplePath = MustAbs("/etc/passwd") + samplePath = check.MustAbs("/etc/passwd") sampleData = []byte(sampleDataString) ) @@ -100,7 +101,7 @@ func TestTmpfileOp(t *testing.T) { {"zero", new(TmpfileOp), new(TmpfileOp), false}, {"differs path", &TmpfileOp{ - Path: MustAbs("/etc/group"), + Path: check.MustAbs("/etc/group"), Data: sampleData, }, &TmpfileOp{ Path: samplePath, diff --git a/container/initproc.go b/container/initproc.go index 28b865e..d0df854 100644 --- a/container/initproc.go +++ b/container/initproc.go @@ -4,18 +4,20 @@ import ( "encoding/gob" "fmt" . "syscall" + + "hakurei.app/container/check" ) func init() { gob.Register(new(MountProcOp)) } // Proc appends an [Op] that mounts a private instance of proc. -func (f *Ops) Proc(target *Absolute) *Ops { +func (f *Ops) Proc(target *check.Absolute) *Ops { *f = append(*f, &MountProcOp{target}) return f } // MountProcOp mounts a new instance of [FstypeProc] on container path Target. -type MountProcOp struct{ Target *Absolute } +type MountProcOp struct{ Target *check.Absolute } func (p *MountProcOp) Valid() bool { return p != nil && p.Target != nil } func (p *MountProcOp) early(*setupState, syscallDispatcher) error { return nil } diff --git a/container/initproc_test.go b/container/initproc_test.go index 48915e0..8633414 100644 --- a/container/initproc_test.go +++ b/container/initproc_test.go @@ -4,6 +4,7 @@ import ( "os" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" ) @@ -11,14 +12,14 @@ func TestMountProcOp(t *testing.T) { checkOpBehaviour(t, []opBehaviourTestCase{ {"mkdir", &Params{ParentPerm: 0755}, &MountProcOp{ - Target: MustAbs("/proc/"), + Target: check.MustAbs("/proc/"), }, nil, nil, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, stub.UniqueError(0)), }, stub.UniqueError(0)}, {"success", &Params{ParentPerm: 0700}, &MountProcOp{ - Target: MustAbs("/proc/"), + Target: check.MustAbs("/proc/"), }, nil, nil, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/sysroot/proc", os.FileMode(0700)}, nil, nil), call("mount", stub.ExpectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, nil), @@ -28,12 +29,12 @@ func TestMountProcOp(t *testing.T) { checkOpsValid(t, []opValidTestCase{ {"nil", (*MountProcOp)(nil), false}, {"zero", new(MountProcOp), false}, - {"valid", &MountProcOp{Target: MustAbs("/proc/")}, true}, + {"valid", &MountProcOp{Target: check.MustAbs("/proc/")}, true}, }) checkOpsBuilder(t, []opsBuilderTestCase{ - {"proc", new(Ops).Proc(MustAbs("/proc/")), Ops{ - &MountProcOp{Target: MustAbs("/proc/")}, + {"proc", new(Ops).Proc(check.MustAbs("/proc/")), Ops{ + &MountProcOp{Target: check.MustAbs("/proc/")}, }}, }) @@ -41,20 +42,20 @@ func TestMountProcOp(t *testing.T) { {"zero", new(MountProcOp), new(MountProcOp), false}, {"target differs", &MountProcOp{ - Target: MustAbs("/proc/nonexistent"), + Target: check.MustAbs("/proc/nonexistent"), }, &MountProcOp{ - Target: MustAbs("/proc/"), + Target: check.MustAbs("/proc/"), }, false}, {"equals", &MountProcOp{ - Target: MustAbs("/proc/"), + Target: check.MustAbs("/proc/"), }, &MountProcOp{ - Target: MustAbs("/proc/"), + Target: check.MustAbs("/proc/"), }, true}, }) checkOpMeta(t, []opMetaTestCase{ - {"proc", &MountProcOp{Target: MustAbs("/proc/")}, + {"proc", &MountProcOp{Target: check.MustAbs("/proc/")}, "mounting", `proc on "/proc/"`}, }) } diff --git a/container/initremount.go b/container/initremount.go index b89ed54..9a3217a 100644 --- a/container/initremount.go +++ b/container/initremount.go @@ -3,19 +3,21 @@ package container import ( "encoding/gob" "fmt" + + "hakurei.app/container/check" ) func init() { gob.Register(new(RemountOp)) } // Remount appends an [Op] that applies [RemountOp.Flags] on container path [RemountOp.Target]. -func (f *Ops) Remount(target *Absolute, flags uintptr) *Ops { +func (f *Ops) Remount(target *check.Absolute, flags uintptr) *Ops { *f = append(*f, &RemountOp{target, flags}) return f } // RemountOp remounts Target with Flags. type RemountOp struct { - Target *Absolute + Target *check.Absolute Flags uintptr } diff --git a/container/initremount_test.go b/container/initremount_test.go index 32a0e8c..74afe0b 100644 --- a/container/initremount_test.go +++ b/container/initremount_test.go @@ -4,13 +4,14 @@ import ( "syscall" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" ) func TestRemountOp(t *testing.T) { checkOpBehaviour(t, []opBehaviourTestCase{ {"success", new(Params), &RemountOp{ - Target: MustAbs("/"), + Target: check.MustAbs("/"), Flags: syscall.MS_RDONLY, }, nil, nil, []stub.Call{ call("remount", stub.ExpectArgs{"/sysroot", uintptr(1)}, nil, nil), @@ -20,13 +21,13 @@ func TestRemountOp(t *testing.T) { checkOpsValid(t, []opValidTestCase{ {"nil", (*RemountOp)(nil), false}, {"zero", new(RemountOp), false}, - {"valid", &RemountOp{Target: MustAbs("/"), Flags: syscall.MS_RDONLY}, true}, + {"valid", &RemountOp{Target: check.MustAbs("/"), Flags: syscall.MS_RDONLY}, true}, }) checkOpsBuilder(t, []opsBuilderTestCase{ - {"root", new(Ops).Remount(MustAbs("/"), syscall.MS_RDONLY), Ops{ + {"root", new(Ops).Remount(check.MustAbs("/"), syscall.MS_RDONLY), Ops{ &RemountOp{ - Target: MustAbs("/"), + Target: check.MustAbs("/"), Flags: syscall.MS_RDONLY, }, }}, @@ -36,33 +37,33 @@ func TestRemountOp(t *testing.T) { {"zero", new(RemountOp), new(RemountOp), false}, {"target differs", &RemountOp{ - Target: MustAbs("/dev/"), + Target: check.MustAbs("/dev/"), Flags: syscall.MS_RDONLY, }, &RemountOp{ - Target: MustAbs("/"), + Target: check.MustAbs("/"), Flags: syscall.MS_RDONLY, }, false}, {"flags differs", &RemountOp{ - Target: MustAbs("/"), + Target: check.MustAbs("/"), Flags: syscall.MS_RDONLY | syscall.MS_NODEV, }, &RemountOp{ - Target: MustAbs("/"), + Target: check.MustAbs("/"), Flags: syscall.MS_RDONLY, }, false}, {"equals", &RemountOp{ - Target: MustAbs("/"), + Target: check.MustAbs("/"), Flags: syscall.MS_RDONLY, }, &RemountOp{ - Target: MustAbs("/"), + Target: check.MustAbs("/"), Flags: syscall.MS_RDONLY, }, true}, }) checkOpMeta(t, []opMetaTestCase{ {"root", &RemountOp{ - Target: MustAbs("/"), + Target: check.MustAbs("/"), Flags: syscall.MS_RDONLY, }, "remounting", `"/" flags 0x1`}, }) diff --git a/container/initsymlink.go b/container/initsymlink.go index 7bd7174..7d722d5 100644 --- a/container/initsymlink.go +++ b/container/initsymlink.go @@ -4,19 +4,21 @@ import ( "encoding/gob" "fmt" "path" + + "hakurei.app/container/check" ) func init() { gob.Register(new(SymlinkOp)) } // Link appends an [Op] that creates a symlink in the container filesystem. -func (f *Ops) Link(target *Absolute, linkName string, dereference bool) *Ops { +func (f *Ops) Link(target *check.Absolute, linkName string, dereference bool) *Ops { *f = append(*f, &SymlinkOp{target, linkName, dereference}) return f } // SymlinkOp optionally dereferences LinkName and creates a symlink at container path Target. type SymlinkOp struct { - Target *Absolute + Target *check.Absolute // LinkName is an arbitrary uninterpreted pathname. LinkName string @@ -28,8 +30,8 @@ func (l *SymlinkOp) Valid() bool { return l != nil && l.Target != nil && l.LinkN func (l *SymlinkOp) early(_ *setupState, k syscallDispatcher) error { if l.Dereference { - if !isAbs(l.LinkName) { - return &AbsoluteError{l.LinkName} + if !path.IsAbs(l.LinkName) { + return &check.AbsoluteError{Pathname: l.LinkName} } if name, err := k.readlink(l.LinkName); err != nil { return err diff --git a/container/initsymlink_test.go b/container/initsymlink_test.go index f90670e..1b69740 100644 --- a/container/initsymlink_test.go +++ b/container/initsymlink_test.go @@ -4,26 +4,27 @@ import ( "os" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" ) func TestSymlinkOp(t *testing.T) { checkOpBehaviour(t, []opBehaviourTestCase{ {"mkdir", &Params{ParentPerm: 0700}, &SymlinkOp{ - Target: MustAbs("/etc/nixos"), + Target: check.MustAbs("/etc/nixos"), LinkName: "/etc/static/nixos", }, nil, nil, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/sysroot/etc", os.FileMode(0700)}, nil, stub.UniqueError(1)), }, stub.UniqueError(1)}, {"abs", &Params{ParentPerm: 0755}, &SymlinkOp{ - Target: MustAbs("/etc/mtab"), + Target: check.MustAbs("/etc/mtab"), LinkName: "etc/mtab", Dereference: true, - }, nil, &AbsoluteError{"etc/mtab"}, nil, nil}, + }, nil, &check.AbsoluteError{Pathname: "etc/mtab"}, nil, nil}, {"readlink", &Params{ParentPerm: 0755}, &SymlinkOp{ - Target: MustAbs("/etc/mtab"), + Target: check.MustAbs("/etc/mtab"), LinkName: "/etc/mtab", Dereference: true, }, []stub.Call{ @@ -31,7 +32,7 @@ func TestSymlinkOp(t *testing.T) { }, stub.UniqueError(0), nil, nil}, {"success noderef", &Params{ParentPerm: 0700}, &SymlinkOp{ - Target: MustAbs("/etc/nixos"), + Target: check.MustAbs("/etc/nixos"), LinkName: "/etc/static/nixos", }, nil, nil, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/sysroot/etc", os.FileMode(0700)}, nil, nil), @@ -39,7 +40,7 @@ func TestSymlinkOp(t *testing.T) { }, nil}, {"success", &Params{ParentPerm: 0755}, &SymlinkOp{ - Target: MustAbs("/etc/mtab"), + Target: check.MustAbs("/etc/mtab"), LinkName: "/etc/mtab", Dereference: true, }, []stub.Call{ @@ -54,18 +55,18 @@ func TestSymlinkOp(t *testing.T) { {"nil", (*SymlinkOp)(nil), false}, {"zero", new(SymlinkOp), false}, {"nil target", &SymlinkOp{LinkName: "/run/current-system"}, false}, - {"zero linkname", &SymlinkOp{Target: MustAbs("/run/current-system")}, false}, - {"valid", &SymlinkOp{Target: MustAbs("/run/current-system"), LinkName: "/run/current-system", Dereference: true}, true}, + {"zero linkname", &SymlinkOp{Target: check.MustAbs("/run/current-system")}, false}, + {"valid", &SymlinkOp{Target: check.MustAbs("/run/current-system"), LinkName: "/run/current-system", Dereference: true}, true}, }) checkOpsBuilder(t, []opsBuilderTestCase{ {"current-system", new(Ops).Link( - MustAbs("/run/current-system"), + check.MustAbs("/run/current-system"), "/run/current-system", true, ), Ops{ &SymlinkOp{ - Target: MustAbs("/run/current-system"), + Target: check.MustAbs("/run/current-system"), LinkName: "/run/current-system", Dereference: true, }, @@ -76,40 +77,40 @@ func TestSymlinkOp(t *testing.T) { {"zero", new(SymlinkOp), new(SymlinkOp), false}, {"target differs", &SymlinkOp{ - Target: MustAbs("/run/current-system/differs"), + Target: check.MustAbs("/run/current-system/differs"), LinkName: "/run/current-system", Dereference: true, }, &SymlinkOp{ - Target: MustAbs("/run/current-system"), + Target: check.MustAbs("/run/current-system"), LinkName: "/run/current-system", Dereference: true, }, false}, {"linkname differs", &SymlinkOp{ - Target: MustAbs("/run/current-system"), + Target: check.MustAbs("/run/current-system"), LinkName: "/run/current-system/differs", Dereference: true, }, &SymlinkOp{ - Target: MustAbs("/run/current-system"), + Target: check.MustAbs("/run/current-system"), LinkName: "/run/current-system", Dereference: true, }, false}, {"dereference differs", &SymlinkOp{ - Target: MustAbs("/run/current-system"), + Target: check.MustAbs("/run/current-system"), LinkName: "/run/current-system", }, &SymlinkOp{ - Target: MustAbs("/run/current-system"), + Target: check.MustAbs("/run/current-system"), LinkName: "/run/current-system", Dereference: true, }, false}, {"equals", &SymlinkOp{ - Target: MustAbs("/run/current-system"), + Target: check.MustAbs("/run/current-system"), LinkName: "/run/current-system", Dereference: true, }, &SymlinkOp{ - Target: MustAbs("/run/current-system"), + Target: check.MustAbs("/run/current-system"), LinkName: "/run/current-system", Dereference: true, }, true}, @@ -117,7 +118,7 @@ func TestSymlinkOp(t *testing.T) { checkOpMeta(t, []opMetaTestCase{ {"current-system", &SymlinkOp{ - Target: MustAbs("/run/current-system"), + Target: check.MustAbs("/run/current-system"), LinkName: "/run/current-system", Dereference: true, }, "creating", `symlink on "/run/current-system" linkname "/run/current-system"`}, diff --git a/container/inittmpfs.go b/container/inittmpfs.go index e8da5fd..23e2a83 100644 --- a/container/inittmpfs.go +++ b/container/inittmpfs.go @@ -7,6 +7,8 @@ import ( "os" "strconv" . "syscall" + + "hakurei.app/container/check" ) func init() { gob.Register(new(MountTmpfsOp)) } @@ -18,13 +20,13 @@ func (e TmpfsSizeError) Error() string { } // Tmpfs appends an [Op] that mounts tmpfs on container path [MountTmpfsOp.Path]. -func (f *Ops) Tmpfs(target *Absolute, size int, perm os.FileMode) *Ops { +func (f *Ops) Tmpfs(target *check.Absolute, size int, perm os.FileMode) *Ops { *f = append(*f, &MountTmpfsOp{SourceTmpfsEphemeral, target, MS_NOSUID | MS_NODEV, size, perm}) return f } // Readonly appends an [Op] that mounts read-only tmpfs on container path [MountTmpfsOp.Path]. -func (f *Ops) Readonly(target *Absolute, perm os.FileMode) *Ops { +func (f *Ops) Readonly(target *check.Absolute, perm os.FileMode) *Ops { *f = append(*f, &MountTmpfsOp{SourceTmpfsReadonly, target, MS_RDONLY | MS_NOSUID | MS_NODEV, 0, perm}) return f } @@ -32,7 +34,7 @@ func (f *Ops) Readonly(target *Absolute, perm os.FileMode) *Ops { // MountTmpfsOp mounts [FstypeTmpfs] on container Path. type MountTmpfsOp struct { FSName string - Path *Absolute + Path *check.Absolute Flags uintptr Size int Perm os.FileMode diff --git a/container/inittmpfs_test.go b/container/inittmpfs_test.go index 9278ee7..f67c45c 100644 --- a/container/inittmpfs_test.go +++ b/container/inittmpfs_test.go @@ -5,6 +5,7 @@ import ( "syscall" "testing" + "hakurei.app/container/check" "hakurei.app/container/stub" ) @@ -24,7 +25,7 @@ func TestMountTmpfsOp(t *testing.T) { {"success", new(Params), &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user/1000/"), + Path: check.MustAbs("/run/user/1000/"), Size: 1 << 10, Perm: 0700, }, nil, nil, []stub.Call{ @@ -42,19 +43,19 @@ func TestMountTmpfsOp(t *testing.T) { {"nil", (*MountTmpfsOp)(nil), false}, {"zero", new(MountTmpfsOp), false}, {"nil path", &MountTmpfsOp{FSName: "tmpfs"}, false}, - {"zero fsname", &MountTmpfsOp{Path: MustAbs("/tmp/")}, false}, - {"valid", &MountTmpfsOp{FSName: "tmpfs", Path: MustAbs("/tmp/")}, true}, + {"zero fsname", &MountTmpfsOp{Path: check.MustAbs("/tmp/")}, false}, + {"valid", &MountTmpfsOp{FSName: "tmpfs", Path: check.MustAbs("/tmp/")}, true}, }) checkOpsBuilder(t, []opsBuilderTestCase{ {"runtime", new(Ops).Tmpfs( - MustAbs("/run/user"), + check.MustAbs("/run/user"), 1<<10, 0755, ), Ops{ &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0755, @@ -62,12 +63,12 @@ func TestMountTmpfsOp(t *testing.T) { }}, {"nscd", new(Ops).Readonly( - MustAbs("/var/run/nscd"), + check.MustAbs("/var/run/nscd"), 0755, ), Ops{ &MountTmpfsOp{ FSName: "readonly", - Path: MustAbs("/var/run/nscd"), + Path: check.MustAbs("/var/run/nscd"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV | syscall.MS_RDONLY, Perm: 0755, }, @@ -79,13 +80,13 @@ func TestMountTmpfsOp(t *testing.T) { {"fsname differs", &MountTmpfsOp{ FSName: "readonly", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0755, }, &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0755, @@ -93,13 +94,13 @@ func TestMountTmpfsOp(t *testing.T) { {"path differs", &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user/differs"), + Path: check.MustAbs("/run/user/differs"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0755, }, &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0755, @@ -107,13 +108,13 @@ func TestMountTmpfsOp(t *testing.T) { {"flags differs", &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV | syscall.MS_RDONLY, Size: 1 << 10, Perm: 0755, }, &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0755, @@ -121,13 +122,13 @@ func TestMountTmpfsOp(t *testing.T) { {"size differs", &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1, Perm: 0755, }, &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0755, @@ -135,13 +136,13 @@ func TestMountTmpfsOp(t *testing.T) { {"perm differs", &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0700, }, &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0755, @@ -149,13 +150,13 @@ func TestMountTmpfsOp(t *testing.T) { {"equals", &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0755, }, &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0755, @@ -165,7 +166,7 @@ func TestMountTmpfsOp(t *testing.T) { checkOpMeta(t, []opMetaTestCase{ {"runtime", &MountTmpfsOp{ FSName: "ephemeral", - Path: MustAbs("/run/user"), + Path: check.MustAbs("/run/user"), Flags: syscall.MS_NOSUID | syscall.MS_NODEV, Size: 1 << 10, Perm: 0755, diff --git a/container/path.go b/container/path.go index fca32c6..bf3f870 100644 --- a/container/path.go +++ b/container/path.go @@ -8,12 +8,17 @@ import ( "strconv" "strings" "syscall" + _ "unsafe" + "hakurei.app/container/check" "hakurei.app/container/vfs" ) /* constants in this file bypass abs check, be extremely careful when changing them! */ +//go:linkname unsafeAbs hakurei.app/container/check.unsafeAbs +func unsafeAbs(_ string) *check.Absolute + const ( // FHSRoot points to the file system root. FHSRoot = "/" @@ -52,31 +57,31 @@ const ( var ( // AbsFHSRoot is [FHSRoot] as [Absolute]. - AbsFHSRoot = &Absolute{FHSRoot} + AbsFHSRoot = unsafeAbs(FHSRoot) // AbsFHSEtc is [FHSEtc] as [Absolute]. - AbsFHSEtc = &Absolute{FHSEtc} + AbsFHSEtc = unsafeAbs(FHSEtc) // AbsFHSTmp is [FHSTmp] as [Absolute]. - AbsFHSTmp = &Absolute{FHSTmp} + AbsFHSTmp = unsafeAbs(FHSTmp) // AbsFHSRun is [FHSRun] as [Absolute]. - AbsFHSRun = &Absolute{FHSRun} + AbsFHSRun = unsafeAbs(FHSRun) // AbsFHSRunUser is [FHSRunUser] as [Absolute]. - AbsFHSRunUser = &Absolute{FHSRunUser} + AbsFHSRunUser = unsafeAbs(FHSRunUser) // AbsFHSUsrBin is [FHSUsrBin] as [Absolute]. - AbsFHSUsrBin = &Absolute{FHSUsrBin} + AbsFHSUsrBin = unsafeAbs(FHSUsrBin) // AbsFHSVar is [FHSVar] as [Absolute]. - AbsFHSVar = &Absolute{FHSVar} + AbsFHSVar = unsafeAbs(FHSVar) // AbsFHSVarLib is [FHSVarLib] as [Absolute]. - AbsFHSVarLib = &Absolute{FHSVarLib} + AbsFHSVarLib = unsafeAbs(FHSVarLib) // AbsFHSDev is [FHSDev] as [Absolute]. - AbsFHSDev = &Absolute{FHSDev} + AbsFHSDev = unsafeAbs(FHSDev) // AbsFHSProc is [FHSProc] as [Absolute]. - AbsFHSProc = &Absolute{FHSProc} + AbsFHSProc = unsafeAbs(FHSProc) // AbsFHSSys is [FHSSys] as [Absolute]. - AbsFHSSys = &Absolute{FHSSys} + AbsFHSSys = unsafeAbs(FHSSys) ) const ( diff --git a/helper/container.go b/helper/container.go index 9bab0df..4708038 100644 --- a/helper/container.go +++ b/helper/container.go @@ -10,6 +10,7 @@ import ( "sync" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/helper/proc" ) @@ -17,7 +18,7 @@ import ( func New( ctx context.Context, msg container.Msg, - pathname *container.Absolute, name string, + pathname *check.Absolute, name string, wt io.WriterTo, stat bool, argF func(argsFd, statFd int) []string, diff --git a/helper/container_test.go b/helper/container_test.go index a3f0a3f..495ea75 100644 --- a/helper/container_test.go +++ b/helper/container_test.go @@ -7,12 +7,13 @@ import ( "testing" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/helper" ) func TestContainer(t *testing.T) { t.Run("start invalid container", func(t *testing.T) { - h := helper.New(t.Context(), nil, container.MustAbs(container.Nonexistent), "hakurei", argsWt, false, argF, nil, nil) + h := helper.New(t.Context(), nil, check.MustAbs(container.Nonexistent), "hakurei", argsWt, false, argF, nil, nil) wantErr := "container: starting an invalid container" if err := h.Start(); err == nil || err.Error() != wantErr { @@ -22,7 +23,7 @@ func TestContainer(t *testing.T) { }) t.Run("valid new helper nil check", func(t *testing.T) { - if got := helper.New(t.Context(), nil, container.MustAbs(container.Nonexistent), "hakurei", argsWt, false, argF, nil, nil); got == nil { + if got := helper.New(t.Context(), nil, check.MustAbs(container.Nonexistent), "hakurei", argsWt, false, argF, nil, nil); got == nil { t.Errorf("New(%q, %q) got nil", argsWt, "hakurei") return @@ -31,7 +32,7 @@ func TestContainer(t *testing.T) { t.Run("implementation compliance", func(t *testing.T) { testHelper(t, func(ctx context.Context, setOutput func(stdoutP, stderrP *io.Writer), stat bool) helper.Helper { - return helper.New(ctx, nil, container.MustAbs(os.Args[0]), "helper", argsWt, stat, argF, func(z *container.Container) { + return helper.New(ctx, nil, check.MustAbs(os.Args[0]), "helper", argsWt, stat, argF, func(z *container.Container) { setOutput(&z.Stdout, &z.Stderr) z. Bind(container.AbsFHSRoot, container.AbsFHSRoot, 0). diff --git a/hst/config.go b/hst/config.go index e661d2d..7c96874 100644 --- a/hst/config.go +++ b/hst/config.go @@ -5,12 +5,12 @@ import ( "strconv" "time" - "hakurei.app/container" + "hakurei.app/container/check" ) const Tmp = "/.hakurei" -var AbsTmp = container.MustAbs(Tmp) +var AbsTmp = check.MustAbs(Tmp) const ( // WaitDelayDefault is used when WaitDelay has its zero value. @@ -107,12 +107,12 @@ type ( // Defaults to passwd name of target uid or chronos. Username string `json:"username,omitempty"` // Pathname of shell in the container filesystem to use for the emulated user. - Shell *container.Absolute `json:"shell"` + Shell *check.Absolute `json:"shell"` // Directory in the container filesystem to enter and use as the home directory of the emulated user. - Home *container.Absolute `json:"home"` + Home *check.Absolute `json:"home"` // Pathname to executable file in the container filesystem. - Path *container.Absolute `json:"path,omitempty"` + Path *check.Absolute `json:"path,omitempty"` // Final args passed to the initial program. Args []string `json:"args"` } @@ -161,11 +161,11 @@ func (config *Config) Validate() error { // ExtraPermConfig describes an acl update op. type ExtraPermConfig struct { - Ensure bool `json:"ensure,omitempty"` - Path *container.Absolute `json:"path"` - Read bool `json:"r,omitempty"` - Write bool `json:"w,omitempty"` - Execute bool `json:"x,omitempty"` + Ensure bool `json:"ensure,omitempty"` + Path *check.Absolute `json:"path"` + Read bool `json:"r,omitempty"` + Write bool `json:"w,omitempty"` + Execute bool `json:"x,omitempty"` } func (e *ExtraPermConfig) String() string { diff --git a/hst/fs.go b/hst/fs.go index 1d33095..4508e97 100644 --- a/hst/fs.go +++ b/hst/fs.go @@ -7,6 +7,7 @@ import ( "reflect" "hakurei.app/container" + "hakurei.app/container/check" ) // FilesystemConfig is an abstract representation of a mount point. @@ -14,9 +15,9 @@ type FilesystemConfig interface { // Valid returns whether the configuration is valid. Valid() bool // Path returns the target path in the container. - Path() *container.Absolute + Path() *check.Absolute // Host returns a slice of all host paths used by this operation. - Host() []*container.Absolute + Host() []*check.Absolute // Apply appends the [container.Op] implementing this operation. Apply(z *ApplyState) diff --git a/hst/fs_test.go b/hst/fs_test.go index 00186d2..35d58ad 100644 --- a/hst/fs_test.go +++ b/hst/fs_test.go @@ -9,6 +9,7 @@ import ( "testing" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" ) @@ -216,11 +217,11 @@ type stubFS struct { typeName string } -func (s stubFS) Valid() bool { return false } -func (s stubFS) Path() *container.Absolute { panic("unreachable") } -func (s stubFS) Host() []*container.Absolute { panic("unreachable") } -func (s stubFS) Apply(*hst.ApplyState) { panic("unreachable") } -func (s stubFS) String() string { return "" } +func (s stubFS) Valid() bool { return false } +func (s stubFS) Path() *check.Absolute { panic("unreachable") } +func (s stubFS) Host() []*check.Absolute { panic("unreachable") } +func (s stubFS) Apply(*hst.ApplyState) { panic("unreachable") } +func (s stubFS) String() string { return "" } type sCheck struct { FS hst.FilesystemConfigJSON `json:"fs"` @@ -232,8 +233,8 @@ type fsTestCase struct { fs hst.FilesystemConfig valid bool ops container.Ops - path *container.Absolute - host []*container.Absolute + path *check.Absolute + host []*check.Absolute str string } @@ -287,11 +288,11 @@ func checkFs(t *testing.T, testCases []fsTestCase) { } } -func m(pathname string) *container.Absolute { return container.MustAbs(pathname) } -func ms(pathnames ...string) []*container.Absolute { - as := make([]*container.Absolute, len(pathnames)) +func m(pathname string) *check.Absolute { return check.MustAbs(pathname) } +func ms(pathnames ...string) []*check.Absolute { + as := make([]*check.Absolute, len(pathnames)) for i, pathname := range pathnames { - as[i] = container.MustAbs(pathname) + as[i] = check.MustAbs(pathname) } return as } diff --git a/hst/fsbind.go b/hst/fsbind.go index 3769fcd..2cebf6b 100644 --- a/hst/fsbind.go +++ b/hst/fsbind.go @@ -5,6 +5,7 @@ import ( "strings" "hakurei.app/container" + "hakurei.app/container/check" ) func init() { gob.Register(new(FSBind)) } @@ -15,9 +16,9 @@ const FilesystemBind = "bind" // FSBind represents a host to container bind mount. type FSBind struct { // mount point in container, same as Source if empty - Target *container.Absolute `json:"dst,omitempty"` + Target *check.Absolute `json:"dst,omitempty"` // host filesystem path to make available to the container - Source *container.Absolute `json:"src"` + Source *check.Absolute `json:"src"` // do not mount Target read-only Write bool `json:"write,omitempty"` // do not disable device files on Target, implies Write @@ -66,7 +67,7 @@ func (b *FSBind) Valid() bool { return true } -func (b *FSBind) Path() *container.Absolute { +func (b *FSBind) Path() *check.Absolute { if !b.Valid() { return nil } @@ -76,11 +77,11 @@ func (b *FSBind) Path() *container.Absolute { return b.Target } -func (b *FSBind) Host() []*container.Absolute { +func (b *FSBind) Host() []*check.Absolute { if !b.Valid() { return nil } - return []*container.Absolute{b.Source} + return []*check.Absolute{b.Source} } func (b *FSBind) Apply(z *ApplyState) { diff --git a/hst/fsephemeral.go b/hst/fsephemeral.go index e09fa8f..631235b 100644 --- a/hst/fsephemeral.go +++ b/hst/fsephemeral.go @@ -5,7 +5,7 @@ import ( "os" "strings" - "hakurei.app/container" + "hakurei.app/container/check" ) func init() { gob.Register(new(FSEphemeral)) } @@ -16,7 +16,7 @@ const FilesystemEphemeral = "ephemeral" // FSEphemeral represents an ephemeral container mount point. type FSEphemeral struct { // mount point in container - Target *container.Absolute `json:"dst,omitempty"` + Target *check.Absolute `json:"dst,omitempty"` // do not mount filesystem read-only Write bool `json:"write,omitempty"` // upper limit on the size of the filesystem @@ -27,14 +27,14 @@ type FSEphemeral struct { func (e *FSEphemeral) Valid() bool { return e != nil && e.Target != nil } -func (e *FSEphemeral) Path() *container.Absolute { +func (e *FSEphemeral) Path() *check.Absolute { if !e.Valid() { return nil } return e.Target } -func (e *FSEphemeral) Host() []*container.Absolute { return nil } +func (e *FSEphemeral) Host() []*check.Absolute { return nil } const fsEphemeralDefaultPerm = os.FileMode(0755) diff --git a/hst/fslink.go b/hst/fslink.go index 40b4fd8..473506e 100644 --- a/hst/fslink.go +++ b/hst/fslink.go @@ -4,7 +4,7 @@ import ( "encoding/gob" "path" - "hakurei.app/container" + "hakurei.app/container/check" ) func init() { gob.Register(new(FSLink)) } @@ -15,7 +15,7 @@ const FilesystemLink = "link" // FSLink represents a symlink in the container filesystem. type FSLink struct { // link path in container - Target *container.Absolute `json:"dst"` + Target *check.Absolute `json:"dst"` // linkname the symlink points to Linkname string `json:"linkname"` // whether to dereference linkname before creating the link @@ -29,14 +29,14 @@ func (l *FSLink) Valid() bool { return !l.Dereference || path.IsAbs(l.Linkname) } -func (l *FSLink) Path() *container.Absolute { +func (l *FSLink) Path() *check.Absolute { if !l.Valid() { return nil } return l.Target } -func (l *FSLink) Host() []*container.Absolute { return nil } +func (l *FSLink) Host() []*check.Absolute { return nil } func (l *FSLink) Apply(z *ApplyState) { if !l.Valid() { diff --git a/hst/fsoverlay.go b/hst/fsoverlay.go index f3c2f37..2c2a195 100644 --- a/hst/fsoverlay.go +++ b/hst/fsoverlay.go @@ -5,6 +5,7 @@ import ( "strings" "hakurei.app/container" + "hakurei.app/container/check" ) func init() { gob.Register(new(FSOverlay)) } @@ -15,14 +16,14 @@ const FilesystemOverlay = "overlay" // FSOverlay represents an overlay mount point. type FSOverlay struct { // mount point in container - Target *container.Absolute `json:"dst"` + Target *check.Absolute `json:"dst"` // any filesystem, does not need to be on a writable filesystem, must not be nil - Lower []*container.Absolute `json:"lower"` + Lower []*check.Absolute `json:"lower"` // the upperdir is normally on a writable filesystem, leave as nil to mount Lower readonly - Upper *container.Absolute `json:"upper,omitempty"` + Upper *check.Absolute `json:"upper,omitempty"` // the workdir needs to be an empty directory on the same filesystem as Upper, must not be nil if Upper is populated - Work *container.Absolute `json:"work,omitempty"` + Work *check.Absolute `json:"work,omitempty"` } func (o *FSOverlay) Valid() bool { @@ -43,18 +44,18 @@ func (o *FSOverlay) Valid() bool { } } -func (o *FSOverlay) Path() *container.Absolute { +func (o *FSOverlay) Path() *check.Absolute { if !o.Valid() { return nil } return o.Target } -func (o *FSOverlay) Host() []*container.Absolute { +func (o *FSOverlay) Host() []*check.Absolute { if !o.Valid() { return nil } - p := make([]*container.Absolute, 0, 2+len(o.Lower)) + p := make([]*check.Absolute, 0, 2+len(o.Lower)) if o.Upper != nil && o.Work != nil { p = append(p, o.Upper, o.Work) } diff --git a/hst/fsoverlay_test.go b/hst/fsoverlay_test.go index 8a5732a..15875bb 100644 --- a/hst/fsoverlay_test.go +++ b/hst/fsoverlay_test.go @@ -4,13 +4,14 @@ import ( "testing" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" ) func TestFSOverlay(t *testing.T) { checkFs(t, []fsTestCase{ {"nil", (*hst.FSOverlay)(nil), false, nil, nil, nil, ""}, - {"nil lower", &hst.FSOverlay{Target: m("/etc"), Lower: []*container.Absolute{nil}}, false, nil, nil, nil, ""}, + {"nil lower", &hst.FSOverlay{Target: m("/etc"), Lower: []*check.Absolute{nil}}, false, nil, nil, nil, ""}, {"zero lower", &hst.FSOverlay{Target: m("/etc"), Upper: m("/"), Work: m("/")}, false, nil, nil, nil, ""}, {"zero lower ro", &hst.FSOverlay{Target: m("/etc")}, false, nil, nil, nil, ""}, {"short lower", &hst.FSOverlay{Target: m("/etc"), Lower: ms("/etc")}, false, nil, nil, nil, ""}, diff --git a/hst/hst.go b/hst/hst.go index 3e4c7de..9145666 100644 --- a/hst/hst.go +++ b/hst/hst.go @@ -7,6 +7,7 @@ import ( "os" "hakurei.app/container" + "hakurei.app/container/check" ) // An AppError is returned while starting an app according to [hst.Config]. @@ -38,13 +39,13 @@ func (e *AppError) Message() string { // Paths contains environment-dependent paths used by hakurei. type Paths struct { // temporary directory returned by [os.TempDir] (usually `/tmp`) - TempDir *container.Absolute `json:"temp_dir"` + TempDir *check.Absolute `json:"temp_dir"` // path to shared directory (usually `/tmp/hakurei.%d`, [Info.User]) - SharePath *container.Absolute `json:"share_path"` + SharePath *check.Absolute `json:"share_path"` // XDG_RUNTIME_DIR value (usually `/run/user/%d`, uid) - RuntimePath *container.Absolute `json:"runtime_path"` + RuntimePath *check.Absolute `json:"runtime_path"` // application runtime directory (usually `/run/user/%d/hakurei`) - RunDirPath *container.Absolute `json:"run_dir_path"` + RunDirPath *check.Absolute `json:"run_dir_path"` } type Info struct { @@ -115,22 +116,22 @@ func Template() *Config { {&FSBind{Target: container.AbsFHSEtc, Source: container.AbsFHSEtc, Special: true}}, {&FSEphemeral{Target: container.AbsFHSTmp, Write: true, Perm: 0755}}, {&FSOverlay{ - Target: container.MustAbs("/nix/store"), - Lower: []*container.Absolute{container.MustAbs("/mnt-root/nix/.ro-store")}, - Upper: container.MustAbs("/mnt-root/nix/.rw-store/upper"), - Work: container.MustAbs("/mnt-root/nix/.rw-store/work"), + Target: check.MustAbs("/nix/store"), + Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, + Upper: check.MustAbs("/mnt-root/nix/.rw-store/upper"), + Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }}, - {&FSBind{Source: container.MustAbs("/nix/store")}}, + {&FSBind{Source: check.MustAbs("/nix/store")}}, {&FSLink{Target: container.AbsFHSRun.Append("current-system"), Linkname: "/run/current-system", Dereference: true}}, {&FSLink{Target: container.AbsFHSRun.Append("opengl-driver"), Linkname: "/run/opengl-driver", Dereference: true}}, {&FSBind{Source: container.AbsFHSVarLib.Append("hakurei/u0/org.chromium.Chromium"), - Target: container.MustAbs("/data/data/org.chromium.Chromium"), Write: true, Ensure: true}}, + Target: check.MustAbs("/data/data/org.chromium.Chromium"), Write: true, Ensure: true}}, {&FSBind{Source: container.AbsFHSDev.Append("dri"), Device: true, Optional: true}}, }, Username: "chronos", Shell: container.AbsFHSRun.Append("current-system/sw/bin/zsh"), - Home: container.MustAbs("/data/data/org.chromium.Chromium"), + Home: check.MustAbs("/data/data/org.chromium.Chromium"), Path: container.AbsFHSRun.Append("current-system/sw/bin/chromium"), Args: []string{ diff --git a/internal/app/app_test.go b/internal/app/app_test.go index d966b6c..851d7c2 100644 --- a/internal/app/app_test.go +++ b/internal/app/app_test.go @@ -16,6 +16,7 @@ import ( "hakurei.app/container" "hakurei.app/container/bits" + "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/internal/app/state" "hakurei.app/system" @@ -695,7 +696,7 @@ func (k *stubNixOS) cmdOutput(cmd *exec.Cmd) ([]byte, error) { func (k *stubNixOS) overflowUid(container.Msg) int { return 65534 } func (k *stubNixOS) overflowGid(container.Msg) int { return 65534 } -func (k *stubNixOS) mustHsuPath() *container.Absolute { return m("/proc/nonexistent/hsu") } +func (k *stubNixOS) mustHsuPath() *check.Absolute { return m("/proc/nonexistent/hsu") } func (k *stubNixOS) fatalf(format string, v ...any) { panic(fmt.Sprintf(format, v...)) } @@ -703,8 +704,8 @@ func (k *stubNixOS) isVerbose() bool { return true } func (k *stubNixOS) verbose(v ...any) { log.Print(v...) } func (k *stubNixOS) verbosef(format string, v ...any) { log.Printf(format, v...) } -func m(pathname string) *container.Absolute { - return container.MustAbs(pathname) +func m(pathname string) *check.Absolute { + return check.MustAbs(pathname) } func f(c hst.FilesystemConfig) hst.FilesystemConfigJSON { diff --git a/internal/app/dispatcher.go b/internal/app/dispatcher.go index 3c5e25c..f375902 100644 --- a/internal/app/dispatcher.go +++ b/internal/app/dispatcher.go @@ -10,6 +10,7 @@ import ( "path/filepath" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/internal" ) @@ -57,7 +58,7 @@ type syscallDispatcher interface { overflowGid(msg container.Msg) int // mustHsuPath provides [internal.MustHsuPath]. - mustHsuPath() *container.Absolute + mustHsuPath() *check.Absolute // fatalf provides [log.Fatalf]. fatalf(format string, v ...any) @@ -92,6 +93,6 @@ func (direct) cmdOutput(cmd *exec.Cmd) ([]byte, error) { return cmd.Output() } func (direct) overflowUid(msg container.Msg) int { return container.OverflowUid(msg) } func (direct) overflowGid(msg container.Msg) int { return container.OverflowGid(msg) } -func (direct) mustHsuPath() *container.Absolute { return internal.MustHsuPath() } +func (direct) mustHsuPath() *check.Absolute { return internal.MustHsuPath() } func (direct) fatalf(format string, v ...any) { log.Fatalf(format, v...) } diff --git a/internal/app/dispatcher_test.go b/internal/app/dispatcher_test.go index 934ab76..834b11b 100644 --- a/internal/app/dispatcher_test.go +++ b/internal/app/dispatcher_test.go @@ -5,6 +5,7 @@ import ( "os/exec" "hakurei.app/container" + "hakurei.app/container/check" ) type panicDispatcher struct{} @@ -22,5 +23,5 @@ func (panicDispatcher) lookupGroupId(string) (string, error) { panic("unreachab func (panicDispatcher) cmdOutput(*exec.Cmd) ([]byte, error) { panic("unreachable") } func (panicDispatcher) overflowUid(container.Msg) int { panic("unreachable") } func (panicDispatcher) overflowGid(container.Msg) int { panic("unreachable") } -func (panicDispatcher) mustHsuPath() *container.Absolute { panic("unreachable") } +func (panicDispatcher) mustHsuPath() *check.Absolute { panic("unreachable") } func (panicDispatcher) fatalf(string, ...any) { panic("unreachable") } diff --git a/internal/app/env.go b/internal/app/env.go index 4305c66..e6d137f 100644 --- a/internal/app/env.go +++ b/internal/app/env.go @@ -3,16 +3,16 @@ package app import ( "strconv" - "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" ) // EnvPaths holds paths copied from the environment and is used to create [hst.Paths]. type EnvPaths struct { // TempDir is returned by [os.TempDir]. - TempDir *container.Absolute + TempDir *check.Absolute // RuntimePath is copied from $XDG_RUNTIME_DIR. - RuntimePath *container.Absolute + RuntimePath *check.Absolute } // Copy expands [EnvPaths] into [hst.Paths]. @@ -43,7 +43,7 @@ func copyPaths(k syscallDispatcher) *EnvPaths { var env EnvPaths - if tempDir, err := container.NewAbs(k.tempdir()); err != nil { + if tempDir, err := check.NewAbs(k.tempdir()); err != nil { k.fatalf("invalid TMPDIR: %v", err) panic("unreachable") } else { @@ -51,7 +51,7 @@ func copyPaths(k syscallDispatcher) *EnvPaths { } r, _ := k.lookupEnv(xdgRuntimeDir) - if a, err := container.NewAbs(r); err == nil { + if a, err := check.NewAbs(r); err == nil { env.RuntimePath = a } diff --git a/internal/app/env_test.go b/internal/app/env_test.go index 04e2134..cf6a18b 100644 --- a/internal/app/env_test.go +++ b/internal/app/env_test.go @@ -6,6 +6,7 @@ import ( "testing" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/container/stub" "hakurei.app/hst" ) @@ -74,11 +75,11 @@ func TestCopyPaths(t *testing.T) { {"invalid tempdir", nil, "\x00", "invalid TMPDIR: path \"\\x00\" is not absolute", EnvPaths{}}, {"empty environment", make(map[string]string), container.Nonexistent, - "", EnvPaths{TempDir: container.MustAbs(container.Nonexistent)}}, + "", EnvPaths{TempDir: check.MustAbs(container.Nonexistent)}}, {"invalid XDG_RUNTIME_DIR", map[string]string{"XDG_RUNTIME_DIR": "\x00"}, container.Nonexistent, - "", EnvPaths{TempDir: container.MustAbs(container.Nonexistent)}}, + "", EnvPaths{TempDir: check.MustAbs(container.Nonexistent)}}, {"full", map[string]string{"XDG_RUNTIME_DIR": "/\x00"}, container.Nonexistent, - "", EnvPaths{TempDir: container.MustAbs(container.Nonexistent), RuntimePath: container.MustAbs("/\x00")}}, + "", EnvPaths{TempDir: check.MustAbs(container.Nonexistent), RuntimePath: check.MustAbs("/\x00")}}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { diff --git a/internal/app/outcome.go b/internal/app/outcome.go index f850d77..e2673e4 100644 --- a/internal/app/outcome.go +++ b/internal/app/outcome.go @@ -4,6 +4,7 @@ import ( "strconv" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/internal/app/state" "hakurei.app/system" @@ -51,7 +52,7 @@ type outcomeState struct { *EnvPaths // Matched paths to cover. Populated by spFilesystemOp. - HidePaths []*container.Absolute + HidePaths []*check.Absolute // Copied via populateLocal. k syscallDispatcher @@ -95,14 +96,14 @@ func (s *outcomeState) populateLocal(k syscallDispatcher, msg container.Msg) err // instancePath returns a path formatted for outcomeStateSys.instance. // This method must only be called from outcomeOp.toContainer if // outcomeOp.toSystem has already called outcomeStateSys.instance. -func (s *outcomeState) instancePath() *container.Absolute { +func (s *outcomeState) instancePath() *check.Absolute { return s.sc.SharePath.Append(s.id.String()) } // runtimePath returns a path formatted for outcomeStateSys.runtime. // This method must only be called from outcomeOp.toContainer if // outcomeOp.toSystem has already called outcomeStateSys.runtime. -func (s *outcomeState) runtimePath() *container.Absolute { +func (s *outcomeState) runtimePath() *check.Absolute { return s.sc.RunDirPath.Append(s.id.String()) } @@ -112,9 +113,9 @@ type outcomeStateSys struct { // Whether XDG_RUNTIME_DIR is used post hsu. useRuntimeDir bool // Process-specific directory in TMPDIR, nil if unused. - sharePath *container.Absolute + sharePath *check.Absolute // Process-specific directory in XDG_RUNTIME_DIR, nil if unused. - runtimeSharePath *container.Absolute + runtimeSharePath *check.Absolute sys *system.I *outcomeState @@ -134,7 +135,7 @@ func (state *outcomeStateSys) ensureRuntimeDir() { // instance returns the pathname to a process-specific directory within TMPDIR. // This directory must only hold entries bound to [system.Process]. -func (state *outcomeStateSys) instance() *container.Absolute { +func (state *outcomeStateSys) instance() *check.Absolute { if state.sharePath != nil { return state.sharePath } @@ -145,7 +146,7 @@ func (state *outcomeStateSys) instance() *container.Absolute { // runtime returns the pathname to a process-specific directory within XDG_RUNTIME_DIR. // This directory must only hold entries bound to [system.Process]. -func (state *outcomeStateSys) runtime() *container.Absolute { +func (state *outcomeStateSys) runtime() *check.Absolute { if state.runtimeSharePath != nil { return state.runtimeSharePath } @@ -169,7 +170,7 @@ type outcomeStateParams struct { // Inner XDG_RUNTIME_DIR default formatting of `/run/user/%d` via mapped uid. // Populated by spRuntimeOp. - runtimeDir *container.Absolute + runtimeDir *check.Absolute as hst.ApplyState *outcomeState diff --git a/internal/app/process.go b/internal/app/process.go index 63f424f..80a256c 100644 --- a/internal/app/process.go +++ b/internal/app/process.go @@ -13,6 +13,7 @@ import ( "time" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/internal" "hakurei.app/internal/app/state" @@ -215,7 +216,7 @@ type finaliseProcess struct { waitDelay time.Duration // Copied from the RunDirPath field of [hst.Paths]. - runDirPath *container.Absolute + runDirPath *check.Absolute // Copied from outcomeState. identity *stringPair[int] diff --git a/internal/app/spcontainer.go b/internal/app/spcontainer.go index ffbee7d..6dd2bca 100644 --- a/internal/app/spcontainer.go +++ b/internal/app/spcontainer.go @@ -9,6 +9,7 @@ import ( "hakurei.app/container" "hakurei.app/container/bits" + "hakurei.app/container/check" "hakurei.app/container/seccomp" "hakurei.app/hst" "hakurei.app/system/dbus" @@ -183,7 +184,7 @@ func (s spFilesystemOp) toSystem(state *outcomeStateSys, _ *hst.Config) error { } } - hidePathSource := make([]*container.Absolute, 0, hidePathSourceCount) + hidePathSource := make([]*check.Absolute, 0, hidePathSourceCount) // fs append for _, c := range filesystem { @@ -234,8 +235,8 @@ func (s spFilesystemOp) toSystem(state *outcomeStateSys, _ *hst.Config) error { // copy matched paths for shim for i, ok := range hidePathMatch { if ok { - if a, err := container.NewAbs(hidePaths[i]); err != nil { - var absoluteError *container.AbsoluteError + if a, err := check.NewAbs(hidePaths[i]); err != nil { + var absoluteError *check.AbsoluteError if !errors.As(err, &absoluteError) { return newWithMessageError(absoluteError.Error(), absoluteError) } diff --git a/internal/app/sppulse.go b/internal/app/sppulse.go index d3742db..a6dba59 100644 --- a/internal/app/sppulse.go +++ b/internal/app/sppulse.go @@ -8,7 +8,7 @@ import ( "os" "syscall" - "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" ) @@ -45,13 +45,13 @@ func (s *spPulseOp) toSystem(state *outcomeStateSys, _ *hst.Config) error { state.sys.Link(pulseSocket, state.runtime().Append("pulse")) // publish current user's pulse cookie for target user - var paCookiePath *container.Absolute + var paCookiePath *check.Absolute { const paLocateStep = "locate PulseAudio cookie" // from environment if p, ok := state.k.lookupEnv("PULSE_COOKIE"); ok { - if a, err := container.NewAbs(p); err != nil { + if a, err := check.NewAbs(p); err != nil { return &hst.AppError{Step: paLocateStep, Err: err} } else { // this takes precedence, do not verify whether the file is accessible @@ -62,7 +62,7 @@ func (s *spPulseOp) toSystem(state *outcomeStateSys, _ *hst.Config) error { // $HOME/.pulse-cookie if p, ok := state.k.lookupEnv("HOME"); ok { - if a, err := container.NewAbs(p); err != nil { + if a, err := check.NewAbs(p); err != nil { return &hst.AppError{Step: paLocateStep, Err: err} } else { paCookiePath = a.Append(".pulse-cookie") @@ -83,7 +83,7 @@ func (s *spPulseOp) toSystem(state *outcomeStateSys, _ *hst.Config) error { // $XDG_CONFIG_HOME/pulse/cookie if p, ok := state.k.lookupEnv("XDG_CONFIG_HOME"); ok { - if a, err := container.NewAbs(p); err != nil { + if a, err := check.NewAbs(p); err != nil { return &hst.AppError{Step: paLocateStep, Err: err} } else { paCookiePath = a.Append("pulse", "cookie") @@ -161,7 +161,7 @@ func (s *spPulseOp) toContainer(state *outcomeStateParams) error { return nil } -func (s *spPulseOp) commonPaths(state *outcomeState) (pulseRuntimeDir, pulseSocket *container.Absolute) { +func (s *spPulseOp) commonPaths(state *outcomeState) (pulseRuntimeDir, pulseSocket *check.Absolute) { // PulseAudio runtime directory (usually `/run/user/%d/pulse`) pulseRuntimeDir = state.sc.RuntimePath.Append("pulse") // PulseAudio socket (usually `/run/user/%d/pulse/native`) diff --git a/internal/app/spruntime.go b/internal/app/spruntime.go index c2e5518..0559718 100644 --- a/internal/app/spruntime.go +++ b/internal/app/spruntime.go @@ -2,6 +2,7 @@ package app import ( "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/system" "hakurei.app/system/acl" @@ -37,7 +38,7 @@ func (s spRuntimeOp) toContainer(state *outcomeStateParams) error { return nil } -func (s spRuntimeOp) commonPaths(state *outcomeState) (runtimeDir, runtimeDirInst *container.Absolute) { +func (s spRuntimeOp) commonPaths(state *outcomeState) (runtimeDir, runtimeDirInst *check.Absolute) { runtimeDir = state.sc.SharePath.Append("runtime") runtimeDirInst = runtimeDir.Append(state.identity.String()) return diff --git a/internal/app/sptmpdir.go b/internal/app/sptmpdir.go index 00680ff..0e5cfe9 100644 --- a/internal/app/sptmpdir.go +++ b/internal/app/sptmpdir.go @@ -2,6 +2,7 @@ package app import ( "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/system" "hakurei.app/system/acl" @@ -26,7 +27,7 @@ func (s spTmpdirOp) toContainer(state *outcomeStateParams) error { return nil } -func (s spTmpdirOp) commonPaths(state *outcomeState) (tmpdir, tmpdirInst *container.Absolute) { +func (s spTmpdirOp) commonPaths(state *outcomeState) (tmpdir, tmpdirInst *check.Absolute) { tmpdir = state.sc.SharePath.Append("tmpdir") tmpdirInst = tmpdir.Append(state.identity.String()) return diff --git a/internal/app/spwayland.go b/internal/app/spwayland.go index 130a2ed..91ce1ac 100644 --- a/internal/app/spwayland.go +++ b/internal/app/spwayland.go @@ -1,7 +1,7 @@ package app import ( - "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/system/acl" "hakurei.app/system/wayland" @@ -10,16 +10,16 @@ import ( // spWaylandOp exports the Wayland display server to the container. type spWaylandOp struct { // Path to host wayland socket. Populated during toSystem if DirectWayland is true. - SocketPath *container.Absolute + SocketPath *check.Absolute } func (s *spWaylandOp) toSystem(state *outcomeStateSys, config *hst.Config) error { // outer wayland socket (usually `/run/user/%d/wayland-%d`) - var socketPath *container.Absolute + var socketPath *check.Absolute if name, ok := state.k.lookupEnv(wayland.WaylandDisplay); !ok { state.msg.Verbose(wayland.WaylandDisplay + " is not set, assuming " + wayland.FallbackName) socketPath = state.sc.RuntimePath.Append(wayland.FallbackName) - } else if a, err := container.NewAbs(name); err != nil { + } else if a, err := check.NewAbs(name); err != nil { socketPath = state.sc.RuntimePath.Append(name) } else { socketPath = a diff --git a/internal/app/spx11.go b/internal/app/spx11.go index 0d287e0..b21eb48 100644 --- a/internal/app/spx11.go +++ b/internal/app/spx11.go @@ -8,6 +8,7 @@ import ( "strings" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/system/acl" ) @@ -29,13 +30,13 @@ func (s *spX11Op) toSystem(state *outcomeStateSys, _ *hst.Config) error { // the socket file at `/tmp/.X11-unix/X%d` is typically owned by the priv user // and not accessible by the target user - var socketPath *container.Absolute + var socketPath *check.Absolute if len(s.Display) > 1 && s.Display[0] == ':' { // `:%d` if n, err := strconv.Atoi(s.Display[1:]); err == nil && n >= 0 { socketPath = absX11SocketDir.Append("X" + strconv.Itoa(n)) } } else if len(s.Display) > 5 && strings.HasPrefix(s.Display, "unix:") { // `unix:%s` - if a, err := container.NewAbs(s.Display[5:]); err == nil { + if a, err := check.NewAbs(s.Display[5:]); err == nil { socketPath = a } } diff --git a/internal/comp.go b/internal/comp.go index 89dc0f8..28ee622 100644 --- a/internal/comp.go +++ b/internal/comp.go @@ -6,11 +6,11 @@ var ( version = compPoison ) -// check validates string value set at compile time. -func check(s string) (string, bool) { return s, s != compPoison && s != "" } +// checkComp validates string value set at compile time. +func checkComp(s string) (string, bool) { return s, s != compPoison && s != "" } func Version() string { - if v, ok := check(version); ok { + if v, ok := checkComp(version); ok { return v } return "impure" diff --git a/internal/path.go b/internal/path.go index fca0fdf..888689f 100644 --- a/internal/path.go +++ b/internal/path.go @@ -3,7 +3,7 @@ package internal import ( "log" - "hakurei.app/container" + "hakurei.app/container/check" ) var ( @@ -12,15 +12,15 @@ var ( ) // MustHakureiPath returns the absolute path to hakurei, configured at compile time. -func MustHakureiPath() *container.Absolute { return mustCheckPath(log.Fatal, "hakurei", hmain) } +func MustHakureiPath() *check.Absolute { return mustCheckPath(log.Fatal, "hakurei", hmain) } // MustHsuPath returns the absolute path to hakurei, configured at compile time. -func MustHsuPath() *container.Absolute { return mustCheckPath(log.Fatal, "hsu", hsu) } +func MustHsuPath() *check.Absolute { return mustCheckPath(log.Fatal, "hsu", hsu) } // mustCheckPath checks a pathname against compPoison, then [container.NewAbs], calling fatal if either step fails. -func mustCheckPath(fatal func(v ...any), name, pathname string) *container.Absolute { +func mustCheckPath(fatal func(v ...any), name, pathname string) *check.Absolute { if pathname != compPoison && pathname != "" { - if a, err := container.NewAbs(pathname); err != nil { + if a, err := check.NewAbs(pathname); err != nil { fatal(err.Error()) return nil // unreachable } else { diff --git a/internal/path_test.go b/internal/path_test.go index 97a8f92..cb4571e 100644 --- a/internal/path_test.go +++ b/internal/path_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "hakurei.app/container" + "hakurei.app/container/check" ) func TestMustCheckPath(t *testing.T) { @@ -35,7 +35,7 @@ func TestMustCheckPath(t *testing.T) { } } - if got := mustCheckPath(fatal, "test", tc.pathname); got != nil && !reflect.DeepEqual(got, container.MustAbs(tc.pathname)) { + if got := mustCheckPath(fatal, "test", tc.pathname); got != nil && !reflect.DeepEqual(got, check.MustAbs(tc.pathname)) { t.Errorf("mustCheckPath: %q", got) } }) diff --git a/ldd/exec.go b/ldd/exec.go index b562316..77b46de 100644 --- a/ldd/exec.go +++ b/ldd/exec.go @@ -10,6 +10,7 @@ import ( "hakurei.app/container" "hakurei.app/container/bits" + "hakurei.app/container/check" "hakurei.app/container/seccomp" ) @@ -27,10 +28,10 @@ func Exec(ctx context.Context, msg container.Msg, p string) ([]*Entry, error) { c, cancel := context.WithTimeout(ctx, lddTimeout) defer cancel() - var toolPath *container.Absolute + var toolPath *check.Absolute if s, err := exec.LookPath(lddName); err != nil { return nil, err - } else if toolPath, err = container.NewAbs(s); err != nil { + } else if toolPath, err = check.NewAbs(s); err != nil { return nil, err } diff --git a/ldd/path.go b/ldd/path.go index a0cdb12..c8290c3 100644 --- a/ldd/path.go +++ b/ldd/path.go @@ -1,20 +1,20 @@ package ldd import ( - "hakurei.app/container" + "hakurei.app/container/check" ) // Path returns a deterministic, deduplicated slice of absolute directory paths in entries. -func Path(entries []*Entry) []*container.Absolute { - p := make([]*container.Absolute, 0, len(entries)*2) +func Path(entries []*Entry) []*check.Absolute { + p := make([]*check.Absolute, 0, len(entries)*2) for _, entry := range entries { - if a, err := container.NewAbs(entry.Path); err == nil { + if a, err := check.NewAbs(entry.Path); err == nil { p = append(p, a.Dir()) } - if a, err := container.NewAbs(entry.Name); err == nil { + if a, err := check.NewAbs(entry.Name); err == nil { p = append(p, a.Dir()) } } - container.SortAbs(p) - return container.CompactAbs(p) + check.SortAbs(p) + return check.CompactAbs(p) } diff --git a/system/acl.go b/system/acl.go index e2e0082..c89a478 100644 --- a/system/acl.go +++ b/system/acl.go @@ -6,19 +6,19 @@ import ( "os" "slices" - "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/system/acl" ) // UpdatePerm calls UpdatePermType with the [Process] criteria. -func (sys *I) UpdatePerm(path *container.Absolute, perms ...acl.Perm) *I { +func (sys *I) UpdatePerm(path *check.Absolute, perms ...acl.Perm) *I { sys.UpdatePermType(Process, path, perms...) return sys } // UpdatePermType maintains [acl.Perms] on a file until its [Enablement] is no longer satisfied. -func (sys *I) UpdatePermType(et hst.Enablement, path *container.Absolute, perms ...acl.Perm) *I { +func (sys *I) UpdatePermType(et hst.Enablement, path *check.Absolute, perms ...acl.Perm) *I { sys.ops = append(sys.ops, &aclUpdateOp{et, path.String(), perms}) return sys } diff --git a/system/dbus.go b/system/dbus.go index 1a0b099..1cc24a2 100644 --- a/system/dbus.go +++ b/system/dbus.go @@ -12,6 +12,7 @@ import ( "syscall" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/system/dbus" ) @@ -21,7 +22,7 @@ var ( ) // MustProxyDBus calls ProxyDBus and panics if an error is returned. -func (sys *I) MustProxyDBus(sessionPath *container.Absolute, session *hst.BusConfig, systemPath *container.Absolute, system *hst.BusConfig) *I { +func (sys *I) MustProxyDBus(sessionPath *check.Absolute, session *hst.BusConfig, systemPath *check.Absolute, system *hst.BusConfig) *I { if err := sys.ProxyDBus(session, system, sessionPath, systemPath); err != nil { panic(err.Error()) } else { @@ -31,7 +32,7 @@ func (sys *I) MustProxyDBus(sessionPath *container.Absolute, session *hst.BusCon // ProxyDBus finalises configuration ahead of time and starts xdg-dbus-proxy via [dbus] and terminates it on revert. // This [Op] is always [Process] scoped. -func (sys *I) ProxyDBus(session, system *hst.BusConfig, sessionPath, systemPath *container.Absolute) error { +func (sys *I) ProxyDBus(session, system *hst.BusConfig, sessionPath, systemPath *check.Absolute) error { d := new(dbusProxyOp) // session bus is required as otherwise this is effectively a very expensive noop diff --git a/system/dbus/proc.go b/system/dbus/proc.go index 01e836d..a4c9300 100644 --- a/system/dbus/proc.go +++ b/system/dbus/proc.go @@ -10,6 +10,7 @@ import ( "hakurei.app/container" "hakurei.app/container/bits" + "hakurei.app/container/check" "hakurei.app/container/seccomp" "hakurei.app/helper" "hakurei.app/ldd" @@ -41,18 +42,18 @@ func (p *Proxy) Start() error { cmd.Env = make([]string, 0) }, nil) } else { - var toolPath *container.Absolute - if a, err := container.NewAbs(p.name); err != nil { + var toolPath *check.Absolute + if a, err := check.NewAbs(p.name); err != nil { if p.name, err = exec.LookPath(p.name); err != nil { return err - } else if toolPath, err = container.NewAbs(p.name); err != nil { + } else if toolPath, err = check.NewAbs(p.name); err != nil { return err } } else { toolPath = a } - var libPaths []*container.Absolute + var libPaths []*check.Absolute if entries, err := ldd.Exec(ctx, p.msg, toolPath.String()); err != nil { return err } else { @@ -76,7 +77,7 @@ func (p *Proxy) Start() error { } // upstream bus directories - upstreamPaths := make([]*container.Absolute, 0, 2) + upstreamPaths := make([]*check.Absolute, 0, 2) for _, addr := range [][]AddrEntry{p.final.SessionUpstream, p.final.SystemUpstream} { for _, ent := range addr { if ent.Method != "unix" { @@ -86,7 +87,7 @@ func (p *Proxy) Start() error { if pair[0] != "path" { continue } - if a, err := container.NewAbs(pair[1]); err != nil { + if a, err := check.NewAbs(pair[1]); err != nil { continue } else { upstreamPaths = append(upstreamPaths, a.Dir()) @@ -94,8 +95,8 @@ func (p *Proxy) Start() error { } } } - container.SortAbs(upstreamPaths) - upstreamPaths = container.CompactAbs(upstreamPaths) + check.SortAbs(upstreamPaths) + upstreamPaths = check.CompactAbs(upstreamPaths) for _, name := range upstreamPaths { z.Bind(name, name, 0) } @@ -103,15 +104,15 @@ func (p *Proxy) Start() error { z.HostAbstract = z.HostNet // parent directories of bind paths - sockDirPaths := make([]*container.Absolute, 0, 2) - if a, err := container.NewAbs(p.final.Session[1]); err == nil { + sockDirPaths := make([]*check.Absolute, 0, 2) + if a, err := check.NewAbs(p.final.Session[1]); err == nil { sockDirPaths = append(sockDirPaths, a.Dir()) } - if a, err := container.NewAbs(p.final.System[1]); err == nil { + if a, err := check.NewAbs(p.final.System[1]); err == nil { sockDirPaths = append(sockDirPaths, a.Dir()) } - container.SortAbs(sockDirPaths) - sockDirPaths = container.CompactAbs(sockDirPaths) + check.SortAbs(sockDirPaths) + sockDirPaths = check.CompactAbs(sockDirPaths) for _, name := range sockDirPaths { z.Bind(name, name, container.BindWritable) } diff --git a/system/link.go b/system/link.go index dcd742c..a13adaa 100644 --- a/system/link.go +++ b/system/link.go @@ -3,17 +3,17 @@ package system import ( "fmt" - "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" ) // Link calls LinkFileType with the [Process] criteria. -func (sys *I) Link(oldname, newname *container.Absolute) *I { +func (sys *I) Link(oldname, newname *check.Absolute) *I { return sys.LinkFileType(Process, oldname, newname) } // LinkFileType maintains a hardlink until its [Enablement] is no longer satisfied. -func (sys *I) LinkFileType(et hst.Enablement, oldname, newname *container.Absolute) *I { +func (sys *I) LinkFileType(et hst.Enablement, oldname, newname *check.Absolute) *I { sys.ops = append(sys.ops, &hardlinkOp{et, newname.String(), oldname.String()}) return sys } diff --git a/system/mkdir.go b/system/mkdir.go index fc6a830..f375579 100644 --- a/system/mkdir.go +++ b/system/mkdir.go @@ -5,18 +5,18 @@ import ( "fmt" "os" - "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" ) // Ensure ensures the existence of a directory. -func (sys *I) Ensure(name *container.Absolute, perm os.FileMode) *I { +func (sys *I) Ensure(name *check.Absolute, perm os.FileMode) *I { sys.ops = append(sys.ops, &mkdirOp{User, name.String(), perm, false}) return sys } // Ephemeral ensures the existence of a directory until its [Enablement] is no longer satisfied. -func (sys *I) Ephemeral(et hst.Enablement, name *container.Absolute, perm os.FileMode) *I { +func (sys *I) Ephemeral(et hst.Enablement, name *check.Absolute, perm os.FileMode) *I { sys.ops = append(sys.ops, &mkdirOp{et, name.String(), perm, true}) return sys } diff --git a/system/system_test.go b/system/system_test.go index 91d8a87..5a361b9 100644 --- a/system/system_test.go +++ b/system/system_test.go @@ -9,6 +9,7 @@ import ( "testing" "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/container/stub" "hakurei.app/hst" "hakurei.app/system/internal/xcb" @@ -313,4 +314,4 @@ func TestNop(t *testing.T) { new(noCopy).Lock() } -func m(pathname string) *container.Absolute { return container.MustAbs(pathname) } +func m(pathname string) *check.Absolute { return check.MustAbs(pathname) } diff --git a/system/tmpfiles.go b/system/tmpfiles.go index 0fe6117..8d94cee 100644 --- a/system/tmpfiles.go +++ b/system/tmpfiles.go @@ -8,12 +8,12 @@ import ( "os" "syscall" - "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" ) // CopyFile reads up to n bytes from src and writes the resulting byte slice to payloadP. -func (sys *I) CopyFile(payloadP *[]byte, src *container.Absolute, cap int, n int64) *I { +func (sys *I) CopyFile(payloadP *[]byte, src *check.Absolute, cap int, n int64) *I { buf := new(bytes.Buffer) buf.Grow(cap) sys.ops = append(sys.ops, &tmpfileOp{payloadP, src.String(), n, buf}) diff --git a/system/wayland.go b/system/wayland.go index f987967..bb144d8 100644 --- a/system/wayland.go +++ b/system/wayland.go @@ -5,7 +5,7 @@ import ( "fmt" "os" - "hakurei.app/container" + "hakurei.app/container/check" "hakurei.app/hst" "hakurei.app/system/acl" "hakurei.app/system/wayland" @@ -20,7 +20,7 @@ type waylandConn interface { // Wayland maintains a wayland socket with security-context-v1 attached via [wayland]. // The socket stops accepting connections once the pipe referred to by sync is closed. // The socket is pathname only and is destroyed on revert. -func (sys *I) Wayland(dst, src *container.Absolute, appID, instanceID string) *I { +func (sys *I) Wayland(dst, src *check.Absolute, appID, instanceID string) *I { sys.ops = append(sys.ops, &waylandOp{nil, dst.String(), src.String(), appID, instanceID,