From 5d18af00077ae6ba8ef686d1fd93d888f69681b2 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 7 Oct 2025 21:29:16 +0900 Subject: [PATCH] container/fhs: move pathname constants This allows referencing FHS pathnames without importing container. Signed-off-by: Ophestra --- cmd/hakurei/command.go | 17 ++++---- cmd/hpkg/app.go | 18 ++++----- cmd/hpkg/main.go | 13 +++--- cmd/hpkg/paths.go | 43 ++++++++++---------- cmd/hpkg/with.go | 9 +++-- container/autoetc.go | 9 +++-- container/autoroot.go | 3 +- container/container.go | 5 ++- container/fhs/abs.go | 41 +++++++++++++++++++ container/fhs/fhs.go | 38 ++++++++++++++++++ container/init.go | 17 ++++---- container/initdev.go | 9 +++-- container/initoverlay.go | 11 +++--- container/initplace.go | 3 +- container/mount.go | 1 - container/path.go | 79 ++----------------------------------- container/sysctl.go | 8 ++-- helper/container_test.go | 7 ++-- hst/config_test.go | 26 ++++++------ hst/fsbind.go | 13 +++--- hst/hst.go | 24 +++++------ internal/app/app_test.go | 23 +++++------ internal/app/env_test.go | 25 ++++++------ internal/app/finalise.go | 3 +- internal/app/hsu.go | 3 +- internal/app/process.go | 3 +- internal/app/spaccount.go | 6 +-- internal/app/spcontainer.go | 17 ++++---- internal/app/spdbus.go | 4 +- internal/app/spruntime.go | 5 ++- internal/app/sptmpdir.go | 3 +- internal/app/spx11.go | 4 +- ldd/exec.go | 7 ++-- 33 files changed, 264 insertions(+), 233 deletions(-) create mode 100644 container/fhs/abs.go create mode 100644 container/fhs/fhs.go diff --git a/cmd/hakurei/command.go b/cmd/hakurei/command.go index 851e0d0..e335647 100644 --- a/cmd/hakurei/command.go +++ b/cmd/hakurei/command.go @@ -17,6 +17,7 @@ import ( "hakurei.app/command" "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/hst" "hakurei.app/internal" "hakurei.app/internal/app" @@ -98,7 +99,7 @@ func buildCommand(ctx context.Context, msg container.Msg, early *earlyHardeningE Gid: us, Username: "chronos", Name: "Hakurei Permissive Default", - HomeDir: container.FHSVarEmpty, + HomeDir: fhs.VarEmpty, } } else { passwd = u @@ -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") + shell := fhs.AbsRoot.Append("bin", "sh") if a, err := check.NewAbs(os.Getenv("SHELL")); err == nil { shell = a } @@ -151,8 +152,8 @@ func buildCommand(ctx context.Context, msg container.Msg, early *earlyHardeningE Filesystem: []hst.FilesystemConfigJSON{ // autoroot, includes the home directory {FilesystemConfig: &hst.FSBind{ - Target: container.AbsFHSRoot, - Source: container.AbsFHSRoot, + Target: fhs.AbsRoot, + Source: fhs.AbsRoot, Write: true, Special: true, }}, @@ -169,7 +170,7 @@ func buildCommand(ctx context.Context, msg container.Msg, early *earlyHardeningE // bind GPU stuff if et&(hst.EX11|hst.EWayland) != 0 { config.Container.Filesystem = append(config.Container.Filesystem, hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{ - Source: container.AbsFHSDev.Append("dri"), + Source: fhs.AbsDev.Append("dri"), Device: true, Optional: true, }}) @@ -178,15 +179,15 @@ func buildCommand(ctx context.Context, msg container.Msg, early *earlyHardeningE config.Container.Filesystem = append(config.Container.Filesystem, // opportunistically bind kvm hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{ - Source: container.AbsFHSDev.Append("kvm"), + Source: fhs.AbsDev.Append("kvm"), Device: true, Optional: true, }}, // do autoetc last hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{ - Target: container.AbsFHSEtc, - Source: container.AbsFHSEtc, + Target: fhs.AbsEtc, + Source: fhs.AbsEtc, Special: true, }}, ) diff --git a/cmd/hpkg/app.go b/cmd/hpkg/app.go index d0092d1..e8bd8b9 100644 --- a/cmd/hpkg/app.go +++ b/cmd/hpkg/app.go @@ -5,8 +5,8 @@ import ( "log" "os" - "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/hst" ) @@ -86,18 +86,18 @@ func (app *appInfo) toHst(pathSet *appPathSet, pathname *check.Absolute, argv [] MapRealUID: app.MapRealUID, Multiarch: app.Multiarch, Filesystem: []hst.FilesystemConfigJSON{ - {FilesystemConfig: &hst.FSBind{Target: container.AbsFHSEtc, Source: pathSet.cacheDir.Append("etc"), Special: true}}, + {FilesystemConfig: &hst.FSBind{Target: fhs.AbsEtc, Source: pathSet.cacheDir.Append("etc"), Special: true}}, {FilesystemConfig: &hst.FSBind{Source: pathSet.nixPath.Append("store"), Target: pathNixStore}}, {FilesystemConfig: &hst.FSLink{Target: pathCurrentSystem, Linkname: app.CurrentSystem.String()}}, {FilesystemConfig: &hst.FSLink{Target: pathBin, Linkname: pathSwBin.String()}}, - {FilesystemConfig: &hst.FSLink{Target: container.AbsFHSUsrBin, Linkname: pathSwBin.String()}}, + {FilesystemConfig: &hst.FSLink{Target: fhs.AbsUsrBin, Linkname: pathSwBin.String()}}, {FilesystemConfig: &hst.FSBind{Source: pathSet.metaPath, Target: hst.AbsTmp.Append("app")}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSEtc.Append("resolv.conf"), Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSSys.Append("block"), Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSSys.Append("bus"), Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSSys.Append("class"), Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSSys.Append("dev"), Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSSys.Append("devices"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsEtc.Append("resolv.conf"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("block"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("bus"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("class"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("dev"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("devices"), Optional: true}}, {FilesystemConfig: &hst.FSBind{Target: pathDataData.Append(app.ID), Source: pathSet.homeDir, Write: true, Ensure: true}}, }, diff --git a/cmd/hpkg/main.go b/cmd/hpkg/main.go index dde0ca2..bb3f886 100644 --- a/cmd/hpkg/main.go +++ b/cmd/hpkg/main.go @@ -13,6 +13,7 @@ import ( "hakurei.app/command" "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/hst" ) @@ -275,12 +276,12 @@ func main() { "path:" + a.NixGL + "#nixVulkanNvidia", }, true, func(config *hst.Config) *hst.Config { config.Container.Filesystem = append(config.Container.Filesystem, []hst.FilesystemConfigJSON{ - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSEtc.Append("resolv.conf"), Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSSys.Append("block"), Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSSys.Append("bus"), Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSSys.Append("class"), Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSSys.Append("dev"), Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSSys.Append("devices"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsEtc.Append("resolv.conf"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("block"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("bus"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("class"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("dev"), Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("devices"), Optional: true}}, }...) appendGPUFilesystem(config) return config diff --git a/cmd/hpkg/paths.go b/cmd/hpkg/paths.go index c1d9ae3..e5c045a 100644 --- a/cmd/hpkg/paths.go +++ b/cmd/hpkg/paths.go @@ -9,6 +9,7 @@ import ( "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/hst" ) @@ -23,16 +24,16 @@ func init() { if a, err := check.NewAbs(os.Getenv("HAKUREI_DATA_HOME")); err == nil { dataHome = a } else { - dataHome = container.AbsFHSVarLib.Append("hakurei/" + strconv.Itoa(os.Getuid())) + dataHome = fhs.AbsVarLib.Append("hakurei/" + strconv.Itoa(os.Getuid())) } } var ( - pathBin = container.AbsFHSRoot.Append("bin") + pathBin = fhs.AbsRoot.Append("bin") pathNix = check.MustAbs("/nix/") pathNixStore = pathNix.Append("store/") - pathCurrentSystem = container.AbsFHSRun.Append("current-system") + pathCurrentSystem = fhs.AbsRun.Append("current-system") pathSwBin = pathCurrentSystem.Append("sw/bin/") pathShell = pathSwBin.Append(bash) @@ -89,28 +90,28 @@ func pathSetByApp(id string) *appPathSet { func appendGPUFilesystem(config *hst.Config) { config.Container.Filesystem = append(config.Container.Filesystem, []hst.FilesystemConfigJSON{ // flatpak commit 763a686d874dd668f0236f911de00b80766ffe79 - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("dri"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("dri"), Device: true, Optional: true}}, // mali - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("mali"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("mali0"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("umplock"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("mali"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("mali0"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("umplock"), Device: true, Optional: true}}, // nvidia - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidiactl"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia-modeset"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidiactl"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia-modeset"), Device: true, Optional: true}}, // nvidia OpenCL/CUDA - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia-uvm"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia-uvm-tools"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia-uvm"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia-uvm-tools"), Device: true, Optional: true}}, // flatpak commit d2dff2875bb3b7e2cd92d8204088d743fd07f3ff - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia0"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia1"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia2"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia3"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia4"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia5"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia6"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia7"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia8"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia9"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia10"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia11"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia12"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia13"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia14"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia15"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia16"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia17"), Device: true, Optional: true}}, - {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia18"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: container.AbsFHSDev.Append("nvidia19"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia0"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia1"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia2"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia3"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia4"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia5"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia6"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia7"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia8"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia9"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia10"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia11"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia12"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia13"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia14"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia15"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia16"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia17"), Device: true, Optional: true}}, + {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia18"), Device: true, Optional: true}}, {FilesystemConfig: &hst.FSBind{Source: fhs.AbsDev.Append("nvidia19"), Device: true, Optional: true}}, }...) } diff --git a/cmd/hpkg/with.go b/cmd/hpkg/with.go index 99de04d..df03a21 100644 --- a/cmd/hpkg/with.go +++ b/cmd/hpkg/with.go @@ -7,6 +7,7 @@ import ( "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/hst" ) @@ -33,11 +34,11 @@ func withNixDaemon( Multiarch: true, Tty: dropShell, Filesystem: []hst.FilesystemConfigJSON{ - {FilesystemConfig: &hst.FSBind{Target: container.AbsFHSEtc, Source: pathSet.cacheDir.Append("etc"), Special: true}}, + {FilesystemConfig: &hst.FSBind{Target: fhs.AbsEtc, Source: pathSet.cacheDir.Append("etc"), Special: true}}, {FilesystemConfig: &hst.FSBind{Source: pathSet.nixPath, Target: pathNix, Write: true}}, {FilesystemConfig: &hst.FSLink{Target: pathCurrentSystem, Linkname: app.CurrentSystem.String()}}, {FilesystemConfig: &hst.FSLink{Target: pathBin, Linkname: pathSwBin.String()}}, - {FilesystemConfig: &hst.FSLink{Target: container.AbsFHSUsrBin, Linkname: pathSwBin.String()}}, + {FilesystemConfig: &hst.FSLink{Target: fhs.AbsUsrBin, Linkname: pathSwBin.String()}}, {FilesystemConfig: &hst.FSBind{Target: pathDataData.Append(app.ID), Source: pathSet.homeDir, Write: true, Ensure: true}}, }, @@ -82,11 +83,11 @@ func withCacheDir( Multiarch: true, Tty: dropShell, Filesystem: []hst.FilesystemConfigJSON{ - {FilesystemConfig: &hst.FSBind{Target: container.AbsFHSEtc, Source: workDir.Append(container.FHSEtc), Special: true}}, + {FilesystemConfig: &hst.FSBind{Target: fhs.AbsEtc, Source: workDir.Append(fhs.Etc), Special: true}}, {FilesystemConfig: &hst.FSBind{Source: workDir.Append("nix"), Target: pathNix}}, {FilesystemConfig: &hst.FSLink{Target: pathCurrentSystem, Linkname: app.CurrentSystem.String()}}, {FilesystemConfig: &hst.FSLink{Target: pathBin, Linkname: pathSwBin.String()}}, - {FilesystemConfig: &hst.FSLink{Target: container.AbsFHSUsrBin, Linkname: pathSwBin.String()}}, + {FilesystemConfig: &hst.FSLink{Target: fhs.AbsUsrBin, Linkname: pathSwBin.String()}}, {FilesystemConfig: &hst.FSBind{Source: workDir, Target: hst.AbsTmp.Append("bundle")}}, {FilesystemConfig: &hst.FSBind{Target: pathDataData.Append(app.ID, "cache"), Source: pathSet.cacheDir, Write: true, Ensure: true}}, }, diff --git a/container/autoetc.go b/container/autoetc.go index 295bdf7..65ab9a2 100644 --- a/container/autoetc.go +++ b/container/autoetc.go @@ -5,6 +5,7 @@ import ( "fmt" "hakurei.app/container/check" + "hakurei.app/container/fhs" ) func init() { gob.Register(new(AutoEtcOp)) } @@ -13,7 +14,7 @@ func init() { gob.Register(new(AutoEtcOp)) } // This is not a generic setup op. It is implemented here to reduce ipc overhead. func (f *Ops) Etc(host *check.Absolute, prefix string) *Ops { e := &AutoEtcOp{prefix} - f.Mkdir(AbsFHSEtc, 0755) + f.Mkdir(fhs.AbsEtc, 0755) f.Bind(host, e.hostPath(), 0) *f = append(*f, e) return f @@ -29,7 +30,7 @@ func (e *AutoEtcOp) apply(state *setupState, k syscallDispatcher) error { } state.nonrepeatable |= nrAutoEtc - const target = sysrootPath + FHSEtc + const target = sysrootPath + fhs.Etc rel := e.hostRel() + "/" if err := k.mkdirAll(target, 0755); err != nil { @@ -44,7 +45,7 @@ func (e *AutoEtcOp) apply(state *setupState, k syscallDispatcher) error { case ".host", "passwd", "group": case "mtab": - if err = k.symlink(FHSProc+"mounts", target+n); err != nil { + if err = k.symlink(fhs.Proc+"mounts", target+n); err != nil { return err } @@ -59,7 +60,7 @@ func (e *AutoEtcOp) apply(state *setupState, k syscallDispatcher) error { return nil } -func (e *AutoEtcOp) hostPath() *check.Absolute { return AbsFHSEtc.Append(e.hostRel()) } +func (e *AutoEtcOp) hostPath() *check.Absolute { return fhs.AbsEtc.Append(e.hostRel()) } func (e *AutoEtcOp) hostRel() string { return ".host/" + e.Prefix } func (e *AutoEtcOp) Is(op Op) bool { diff --git a/container/autoroot.go b/container/autoroot.go index 519aada..0ebe6b2 100644 --- a/container/autoroot.go +++ b/container/autoroot.go @@ -5,6 +5,7 @@ import ( "fmt" "hakurei.app/container/check" + "hakurei.app/container/fhs" ) func init() { gob.Register(new(AutoRootOp)) } @@ -40,7 +41,7 @@ func (r *AutoRootOp) early(state *setupState, k syscallDispatcher) error { // careful: the Valid method is skipped, make sure this is always valid op := &BindMountOp{ Source: r.Host.Append(name), - Target: AbsFHSRoot.Append(name), + Target: fhs.AbsRoot.Append(name), Flags: r.Flags, } if err = op.early(state, k); err != nil { diff --git a/container/container.go b/container/container.go index 08dc9e4..5b6514d 100644 --- a/container/container.go +++ b/container/container.go @@ -16,6 +16,7 @@ import ( "hakurei.app/container/bits" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/container/seccomp" ) @@ -200,7 +201,7 @@ func (p *Container) Start() error { } else { p.cmd.Cancel = func() error { return p.cmd.Process.Signal(CancelSignal) } } - p.cmd.Dir = FHSRoot + p.cmd.Dir = fhs.Root p.cmd.SysProcAttr = &SysProcAttr{ Setsid: !p.RetainSession, Pdeathsig: SIGKILL, @@ -316,7 +317,7 @@ func (p *Container) Serve() error { // do not transmit nil if p.Dir == nil { - p.Dir = AbsFHSRoot + p.Dir = fhs.AbsRoot } if p.SeccompRules == nil { p.SeccompRules = make([]seccomp.NativeRule, 0) diff --git a/container/fhs/abs.go b/container/fhs/abs.go new file mode 100644 index 0000000..af3588b --- /dev/null +++ b/container/fhs/abs.go @@ -0,0 +1,41 @@ +package fhs + +import ( + _ "unsafe" + + "hakurei.app/container/check" +) + +/* 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 + +var ( + // AbsRoot is [Root] as [check.Absolute]. + AbsRoot = unsafeAbs(Root) + // AbsEtc is [Etc] as [check.Absolute]. + AbsEtc = unsafeAbs(Etc) + // AbsTmp is [Tmp] as [check.Absolute]. + AbsTmp = unsafeAbs(Tmp) + + // AbsRun is [Run] as [check.Absolute]. + AbsRun = unsafeAbs(Run) + // AbsRunUser is [RunUser] as [check.Absolute]. + AbsRunUser = unsafeAbs(RunUser) + + // AbsUsrBin is [UsrBin] as [check.Absolute]. + AbsUsrBin = unsafeAbs(UsrBin) + + // AbsVar is [Var] as [check.Absolute]. + AbsVar = unsafeAbs(Var) + // AbsVarLib is [VarLib] as [check.Absolute]. + AbsVarLib = unsafeAbs(VarLib) + + // AbsDev is [Dev] as [check.Absolute]. + AbsDev = unsafeAbs(Dev) + // AbsProc is [Proc] as [check.Absolute]. + AbsProc = unsafeAbs(Proc) + // AbsSys is [Sys] as [check.Absolute]. + AbsSys = unsafeAbs(Sys) +) diff --git a/container/fhs/fhs.go b/container/fhs/fhs.go new file mode 100644 index 0000000..6a3a304 --- /dev/null +++ b/container/fhs/fhs.go @@ -0,0 +1,38 @@ +// Package fhs provides constant and checked pathname values for common FHS paths. +package fhs + +const ( + // Root points to the file system root. + Root = "/" + // Etc points to the directory for system-specific configuration. + Etc = "/etc/" + // Tmp points to the place for small temporary files. + Tmp = "/tmp/" + + // Run points to a "tmpfs" file system for system packages to place runtime data, socket files, and similar. + Run = "/run/" + // RunUser points to a directory containing per-user runtime directories, + // each usually individually mounted "tmpfs" instances. + RunUser = Run + "user/" + + // Usr points to vendor-supplied operating system resources. + Usr = "/usr/" + // UsrBin points to binaries and executables for user commands that shall appear in the $PATH search path. + UsrBin = Usr + "bin/" + + // Var points to persistent, variable system data. Writable during normal system operation. + Var = "/var/" + // VarLib points to persistent system data. + VarLib = Var + "lib/" + // VarEmpty points to a nonstandard directory that is usually empty. + VarEmpty = Var + "empty/" + + // Dev points to the root directory for device nodes. + Dev = "/dev/" + // Proc points to a virtual kernel file system exposing the process list and other functionality. + Proc = "/proc/" + // ProcSys points to a hierarchy below /proc/ that exposes a number of kernel tunables. + ProcSys = Proc + "sys/" + // Sys points to a virtual kernel file system exposing discovered devices and other functionality. + Sys = "/sys/" +) diff --git a/container/init.go b/container/init.go index e65472e..9481acd 100644 --- a/container/init.go +++ b/container/init.go @@ -12,6 +12,7 @@ import ( . "syscall" "time" + "hakurei.app/container/fhs" "hakurei.app/container/seccomp" ) @@ -30,7 +31,7 @@ const ( it should be noted that none of this should become relevant at any point since the resulting intermediate root tmpfs should be effectively anonymous */ - intermediateHostPath = FHSProc + "self/fd" + intermediateHostPath = fhs.Proc + "self/fd" // setup params file descriptor setupEnv = "HAKUREI_SETUP" @@ -146,17 +147,17 @@ func initEntrypoint(k syscallDispatcher, msg Msg) { if err := k.setDumpable(SUID_DUMP_USER); err != nil { k.fatalf(msg, "cannot set SUID_DUMP_USER: %v", err) } - if err := k.writeFile(FHSProc+"self/uid_map", + if err := k.writeFile(fhs.Proc+"self/uid_map", append([]byte{}, strconv.Itoa(params.Uid)+" "+strconv.Itoa(params.HostUid)+" 1\n"...), 0); err != nil { k.fatalf(msg, "%v", err) } - if err := k.writeFile(FHSProc+"self/setgroups", + if err := k.writeFile(fhs.Proc+"self/setgroups", []byte("deny\n"), 0); err != nil && !os.IsNotExist(err) { k.fatalf(msg, "%v", err) } - if err := k.writeFile(FHSProc+"self/gid_map", + if err := k.writeFile(fhs.Proc+"self/gid_map", append([]byte{}, strconv.Itoa(params.Gid)+" "+strconv.Itoa(params.HostGid)+" 1\n"...), 0); err != nil { k.fatalf(msg, "%v", err) @@ -175,7 +176,7 @@ func initEntrypoint(k syscallDispatcher, msg Msg) { // cache sysctl before pivot_root lastcap := k.lastcap(msg) - if err := k.mount(zeroString, FHSRoot, zeroString, MS_SILENT|MS_SLAVE|MS_REC, zeroString); err != nil { + if err := k.mount(zeroString, fhs.Root, zeroString, MS_SILENT|MS_SLAVE|MS_REC, zeroString); err != nil { k.fatalf(msg, "cannot make / rslave: %v", err) } @@ -220,7 +221,7 @@ func initEntrypoint(k syscallDispatcher, msg Msg) { if err := k.pivotRoot(intermediateHostPath, hostDir); err != nil { k.fatalf(msg, "cannot pivot into intermediate root: %v", err) } - if err := k.chdir(FHSRoot); err != nil { + if err := k.chdir(fhs.Root); err != nil { k.fatalf(msg, "cannot enter intermediate root: %v", err) } @@ -253,7 +254,7 @@ func initEntrypoint(k syscallDispatcher, msg Msg) { { var fd int if err := IgnoringEINTR(func() (err error) { - fd, err = k.open(FHSRoot, O_DIRECTORY|O_RDONLY, 0) + fd, err = k.open(fhs.Root, O_DIRECTORY|O_RDONLY, 0) return }); err != nil { k.fatalf(msg, "cannot open intermediate root: %v", err) @@ -271,7 +272,7 @@ func initEntrypoint(k syscallDispatcher, msg Msg) { if err := k.unmount(".", MNT_DETACH); err != nil { k.fatalf(msg, "cannot unmount intermediate root: %v", err) } - if err := k.chdir(FHSRoot); err != nil { + if err := k.chdir(fhs.Root); err != nil { k.fatalf(msg, "cannot enter root: %v", err) } diff --git a/container/initdev.go b/container/initdev.go index e7c4eab..89a6613 100644 --- a/container/initdev.go +++ b/container/initdev.go @@ -7,6 +7,7 @@ import ( . "syscall" "hakurei.app/container/check" + "hakurei.app/container/fhs" ) func init() { gob.Register(new(MountDevOp)) } @@ -49,7 +50,7 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error { } if err := k.bindMount( state, - toHost(FHSDev+name), + toHost(fhs.Dev+name), targetPath, 0, ); err != nil { @@ -58,15 +59,15 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error { } for i, name := range []string{"stdin", "stdout", "stderr"} { if err := k.symlink( - FHSProc+"self/fd/"+string(rune(i+'0')), + fhs.Proc+"self/fd/"+string(rune(i+'0')), path.Join(target, name), ); err != nil { return err } } for _, pair := range [][2]string{ - {FHSProc + "self/fd", "fd"}, - {FHSProc + "kcore", "core"}, + {fhs.Proc + "self/fd", "fd"}, + {fhs.Proc + "kcore", "core"}, {"pts/ptmx", "ptmx"}, } { if err := k.symlink(pair[0], path.Join(target, pair[1])); err != nil { diff --git a/container/initoverlay.go b/container/initoverlay.go index 74d925a..74ae7d0 100644 --- a/container/initoverlay.go +++ b/container/initoverlay.go @@ -7,6 +7,7 @@ import ( "strings" "hakurei.app/container/check" + "hakurei.app/container/fhs" ) const ( @@ -67,7 +68,7 @@ func (f *Ops) Overlay(target, state, work *check.Absolute, layers ...*check.Abso // OverlayEphemeral appends an [Op] that mounts the overlay pseudo filesystem on [MountOverlayOp.Target] // with an ephemeral upperdir and workdir. func (f *Ops) OverlayEphemeral(target *check.Absolute, layers ...*check.Absolute) *Ops { - return f.Overlay(target, AbsFHSRoot, nil, layers...) + return f.Overlay(target, fhs.AbsRoot, nil, layers...) } // OverlayReadonly appends an [Op] that mounts the overlay pseudo filesystem readonly on [MountOverlayOp.Target] @@ -85,7 +86,7 @@ type MountOverlayOp struct { lower []string // The upperdir is normally on a writable filesystem. // - // If Work is nil and Upper holds the special value [AbsFHSRoot], + // If Work is nil and Upper holds the special value [fhs.AbsRoot], // 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. @@ -119,7 +120,7 @@ func (o *MountOverlayOp) Valid() bool { func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error { if o.Work == nil && o.Upper != nil { switch o.Upper.String() { - case FHSRoot: // ephemeral + case fhs.Root: // ephemeral o.ephemeral = true // intermediate root not yet available default: @@ -174,10 +175,10 @@ func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error { if o.ephemeral { var err error // these directories are created internally, therefore early (absolute, symlink, prefix, escape) is bypassed - if o.upper, err = k.mkdirTemp(FHSRoot, intermediatePatternOverlayUpper); err != nil { + if o.upper, err = k.mkdirTemp(fhs.Root, intermediatePatternOverlayUpper); err != nil { return err } - if o.work, err = k.mkdirTemp(FHSRoot, intermediatePatternOverlayWork); err != nil { + if o.work, err = k.mkdirTemp(fhs.Root, intermediatePatternOverlayWork); err != nil { return err } } diff --git a/container/initplace.go b/container/initplace.go index 1f41846..d08cf65 100644 --- a/container/initplace.go +++ b/container/initplace.go @@ -6,6 +6,7 @@ import ( "syscall" "hakurei.app/container/check" + "hakurei.app/container/fhs" ) const ( @@ -40,7 +41,7 @@ func (t *TmpfileOp) Valid() bool { return t != ni func (t *TmpfileOp) early(*setupState, syscallDispatcher) error { return nil } func (t *TmpfileOp) apply(state *setupState, k syscallDispatcher) error { var tmpPath string - if f, err := k.createTemp(FHSRoot, intermediatePatternTmpfile); err != nil { + if f, err := k.createTemp(fhs.Root, intermediatePatternTmpfile); err != nil { return err } else if _, err = f.Write(t.Data); err != nil { return err diff --git a/container/mount.go b/container/mount.go index dbd39cb..2749d0e 100644 --- a/container/mount.go +++ b/container/mount.go @@ -59,7 +59,6 @@ const ( FstypeNULL = zeroString // FstypeProc represents the proc pseudo-filesystem. // A fully visible instance of proc must be available in the mount namespace for proc to be mounted. - // This filesystem type is usually mounted on [FHSProc]. FstypeProc = "proc" // FstypeDevpts represents the devpts pseudo-filesystem. // This type of filesystem is usually mounted on /dev/pts. diff --git a/container/path.go b/container/path.go index bf3f870..bc0000a 100644 --- a/container/path.go +++ b/container/path.go @@ -8,90 +8,19 @@ import ( "strconv" "strings" "syscall" - _ "unsafe" - "hakurei.app/container/check" + "hakurei.app/container/fhs" "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 = "/" - // FHSEtc points to the directory for system-specific configuration. - FHSEtc = "/etc/" - // FHSTmp points to the place for small temporary files. - FHSTmp = "/tmp/" - - // FHSRun points to a "tmpfs" file system for system packages to place runtime data, socket files, and similar. - FHSRun = "/run/" - // FHSRunUser points to a directory containing per-user runtime directories, - // each usually individually mounted "tmpfs" instances. - FHSRunUser = FHSRun + "user/" - - // FHSUsr points to vendor-supplied operating system resources. - FHSUsr = "/usr/" - // FHSUsrBin points to binaries and executables for user commands that shall appear in the $PATH search path. - FHSUsrBin = FHSUsr + "bin/" - - // FHSVar points to persistent, variable system data. Writable during normal system operation. - FHSVar = "/var/" - // FHSVarLib points to persistent system data. - FHSVarLib = FHSVar + "lib/" - // FHSVarEmpty points to a nonstandard directory that is usually empty. - FHSVarEmpty = FHSVar + "empty/" - - // FHSDev points to the root directory for device nodes. - FHSDev = "/dev/" - // FHSProc points to a virtual kernel file system exposing the process list and other functionality. - FHSProc = "/proc/" - // FHSProcSys points to a hierarchy below /proc/ that exposes a number of kernel tunables. - FHSProcSys = FHSProc + "sys/" - // FHSSys points to a virtual kernel file system exposing discovered devices and other functionality. - FHSSys = "/sys/" -) - -var ( - // AbsFHSRoot is [FHSRoot] as [Absolute]. - AbsFHSRoot = unsafeAbs(FHSRoot) - // AbsFHSEtc is [FHSEtc] as [Absolute]. - AbsFHSEtc = unsafeAbs(FHSEtc) - // AbsFHSTmp is [FHSTmp] as [Absolute]. - AbsFHSTmp = unsafeAbs(FHSTmp) - - // AbsFHSRun is [FHSRun] as [Absolute]. - AbsFHSRun = unsafeAbs(FHSRun) - // AbsFHSRunUser is [FHSRunUser] as [Absolute]. - AbsFHSRunUser = unsafeAbs(FHSRunUser) - - // AbsFHSUsrBin is [FHSUsrBin] as [Absolute]. - AbsFHSUsrBin = unsafeAbs(FHSUsrBin) - - // AbsFHSVar is [FHSVar] as [Absolute]. - AbsFHSVar = unsafeAbs(FHSVar) - // AbsFHSVarLib is [FHSVarLib] as [Absolute]. - AbsFHSVarLib = unsafeAbs(FHSVarLib) - - // AbsFHSDev is [FHSDev] as [Absolute]. - AbsFHSDev = unsafeAbs(FHSDev) - // AbsFHSProc is [FHSProc] as [Absolute]. - AbsFHSProc = unsafeAbs(FHSProc) - // AbsFHSSys is [FHSSys] as [Absolute]. - AbsFHSSys = unsafeAbs(FHSSys) -) - const ( // Nonexistent is a path that cannot exist. // /proc is chosen because a system with covered /proc is unsupported by this package. - Nonexistent = FHSProc + "nonexistent" + Nonexistent = fhs.Proc + "nonexistent" - hostPath = FHSRoot + hostDir + hostPath = fhs.Root + hostDir hostDir = "host" - sysrootPath = FHSRoot + sysrootDir + sysrootPath = fhs.Root + sysrootDir sysrootDir = "sysroot" ) diff --git a/container/sysctl.go b/container/sysctl.go index 327872b..9a1e818 100644 --- a/container/sysctl.go +++ b/container/sysctl.go @@ -5,6 +5,8 @@ import ( "os" "strconv" "sync" + + "hakurei.app/container/fhs" ) var ( @@ -16,9 +18,9 @@ var ( ) const ( - kernelOverflowuidPath = FHSProcSys + "kernel/overflowuid" - kernelOverflowgidPath = FHSProcSys + "kernel/overflowgid" - kernelCapLastCapPath = FHSProcSys + "kernel/cap_last_cap" + kernelOverflowuidPath = fhs.ProcSys + "kernel/overflowuid" + kernelOverflowgidPath = fhs.ProcSys + "kernel/overflowgid" + kernelCapLastCapPath = fhs.ProcSys + "kernel/cap_last_cap" ) func mustReadSysctl(msg Msg) { diff --git a/helper/container_test.go b/helper/container_test.go index 495ea75..922d825 100644 --- a/helper/container_test.go +++ b/helper/container_test.go @@ -8,6 +8,7 @@ import ( "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/helper" ) @@ -35,9 +36,9 @@ func TestContainer(t *testing.T) { 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). - Proc(container.AbsFHSProc). - Dev(container.AbsFHSDev, true) + Bind(fhs.AbsRoot, fhs.AbsRoot, 0). + Proc(fhs.AbsProc). + Dev(fhs.AbsDev, true) }, nil) }) }) diff --git a/hst/config_test.go b/hst/config_test.go index f57be3d..ea50d4f 100644 --- a/hst/config_test.go +++ b/hst/config_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "hakurei.app/container" + "hakurei.app/container/fhs" "hakurei.app/hst" ) @@ -25,18 +25,18 @@ func TestConfigValidate(t *testing.T) { {"home", &hst.Config{Container: &hst.ContainerConfig{}}, &hst.AppError{Step: "validate configuration", Err: hst.ErrConfigNull, Msg: "container configuration missing path to home directory"}}, {"shell", &hst.Config{Container: &hst.ContainerConfig{ - Home: container.AbsFHSTmp, + Home: fhs.AbsTmp, }}, &hst.AppError{Step: "validate configuration", Err: hst.ErrConfigNull, Msg: "container configuration missing path to shell"}}, {"path", &hst.Config{Container: &hst.ContainerConfig{ - Home: container.AbsFHSTmp, - Shell: container.AbsFHSTmp, + Home: fhs.AbsTmp, + Shell: fhs.AbsTmp, }}, &hst.AppError{Step: "validate configuration", Err: hst.ErrConfigNull, Msg: "container configuration missing path to initial program"}}, {"valid", &hst.Config{Container: &hst.ContainerConfig{ - Home: container.AbsFHSTmp, - Shell: container.AbsFHSTmp, - Path: container.AbsFHSTmp, + Home: fhs.AbsTmp, + Shell: fhs.AbsTmp, + Path: fhs.AbsTmp, }}, nil}, } for _, tc := range testCases { @@ -56,14 +56,14 @@ func TestExtraPermConfig(t *testing.T) { }{ {"nil", nil, ""}, {"nil path", &hst.ExtraPermConfig{Path: nil}, ""}, - {"r", &hst.ExtraPermConfig{Path: container.AbsFHSRoot, Read: true}, "r--:/"}, - {"r+", &hst.ExtraPermConfig{Ensure: true, Path: container.AbsFHSRoot, Read: true}, "r--+:/"}, + {"r", &hst.ExtraPermConfig{Path: fhs.AbsRoot, Read: true}, "r--:/"}, + {"r+", &hst.ExtraPermConfig{Ensure: true, Path: fhs.AbsRoot, Read: true}, "r--+:/"}, {"w", &hst.ExtraPermConfig{Path: hst.AbsTmp, Write: true}, "-w-:/.hakurei"}, {"w+", &hst.ExtraPermConfig{Ensure: true, Path: hst.AbsTmp, Write: true}, "-w-+:/.hakurei"}, - {"x", &hst.ExtraPermConfig{Path: container.AbsFHSRunUser, Execute: true}, "--x:/run/user/"}, - {"x+", &hst.ExtraPermConfig{Ensure: true, Path: container.AbsFHSRunUser, Execute: true}, "--x+:/run/user/"}, - {"rwx", &hst.ExtraPermConfig{Path: container.AbsFHSTmp, Read: true, Write: true, Execute: true}, "rwx:/tmp/"}, - {"rwx+", &hst.ExtraPermConfig{Ensure: true, Path: container.AbsFHSTmp, Read: true, Write: true, Execute: true}, "rwx+:/tmp/"}, + {"x", &hst.ExtraPermConfig{Path: fhs.AbsRunUser, Execute: true}, "--x:/run/user/"}, + {"x+", &hst.ExtraPermConfig{Ensure: true, Path: fhs.AbsRunUser, Execute: true}, "--x+:/run/user/"}, + {"rwx", &hst.ExtraPermConfig{Path: fhs.AbsTmp, Read: true, Write: true, Execute: true}, "rwx:/tmp/"}, + {"rwx+", &hst.ExtraPermConfig{Ensure: true, Path: fhs.AbsTmp, Read: true, Write: true, Execute: true}, "rwx+:/tmp/"}, } for _, tc := range testCases { diff --git a/hst/fsbind.go b/hst/fsbind.go index 2cebf6b..8b7b5fe 100644 --- a/hst/fsbind.go +++ b/hst/fsbind.go @@ -6,6 +6,7 @@ import ( "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" ) func init() { gob.Register(new(FSBind)) } @@ -29,19 +30,19 @@ type FSBind struct { Optional bool `json:"optional,omitempty"` // enable special behaviour: - // for autoroot, Target must be set to [container.AbsFHSRoot]; - // for autoetc, Target must be set to [container.AbsFHSEtc] + // for autoroot, Target must be set to [fhs.AbsRoot]; + // for autoetc, Target must be set to [fhs.AbsEtc] Special bool `json:"special,omitempty"` } // IsAutoRoot returns whether this FSBind has autoroot behaviour enabled. func (b *FSBind) IsAutoRoot() bool { - return b.Valid() && b.Special && b.Target.String() == container.FHSRoot + return b.Valid() && b.Special && b.Target.String() == fhs.Root } // IsAutoEtc returns whether this FSBind has autoetc behaviour enabled. func (b *FSBind) IsAutoEtc() bool { - return b.Valid() && b.Special && b.Target.String() == container.FHSEtc + return b.Valid() && b.Special && b.Target.String() == fhs.Etc } func (b *FSBind) Valid() bool { @@ -56,7 +57,7 @@ func (b *FSBind) Valid() bool { return false } else { switch b.Target.String() { - case container.FHSRoot, container.FHSEtc: + case fhs.Root, fhs.Etc: break default: @@ -138,7 +139,7 @@ func (b *FSBind) String() string { if flagSym != "" { prefix += ":" + flagSym } - if b.Source.String() != container.FHSRoot { + if b.Source.String() != fhs.Root { return prefix + ":" + b.Source.String() } return prefix diff --git a/hst/hst.go b/hst/hst.go index 9145666..fa94956 100644 --- a/hst/hst.go +++ b/hst/hst.go @@ -6,8 +6,8 @@ import ( "net" "os" - "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" ) // An AppError is returned while starting an app according to [hst.Config]. @@ -85,8 +85,8 @@ func Template() *Config { DirectWayland: false, ExtraPerms: []*ExtraPermConfig{ - {Path: container.AbsFHSVarLib.Append("hakurei/u0"), Ensure: true, Execute: true}, - {Path: container.AbsFHSVarLib.Append("hakurei/u0/org.chromium.Chromium"), Read: true, Write: true, Execute: true}, + {Path: fhs.AbsVarLib.Append("hakurei/u0"), Ensure: true, Execute: true}, + {Path: fhs.AbsVarLib.Append("hakurei/u0/org.chromium.Chromium"), Read: true, Write: true, Execute: true}, }, Identity: 9, @@ -112,9 +112,9 @@ func Template() *Config { "GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT", }, Filesystem: []FilesystemConfigJSON{ - {&FSBind{Target: container.AbsFHSRoot, Source: container.AbsFHSVarLib.Append("hakurei/base/org.debian"), Write: true, Special: true}}, - {&FSBind{Target: container.AbsFHSEtc, Source: container.AbsFHSEtc, Special: true}}, - {&FSEphemeral{Target: container.AbsFHSTmp, Write: true, Perm: 0755}}, + {&FSBind{Target: fhs.AbsRoot, Source: fhs.AbsVarLib.Append("hakurei/base/org.debian"), Write: true, Special: true}}, + {&FSBind{Target: fhs.AbsEtc, Source: fhs.AbsEtc, Special: true}}, + {&FSEphemeral{Target: fhs.AbsTmp, Write: true, Perm: 0755}}, {&FSOverlay{ Target: check.MustAbs("/nix/store"), Lower: []*check.Absolute{check.MustAbs("/mnt-root/nix/.ro-store")}, @@ -122,18 +122,18 @@ func Template() *Config { Work: check.MustAbs("/mnt-root/nix/.rw-store/work"), }}, {&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"), + {&FSLink{Target: fhs.AbsRun.Append("current-system"), Linkname: "/run/current-system", Dereference: true}}, + {&FSLink{Target: fhs.AbsRun.Append("opengl-driver"), Linkname: "/run/opengl-driver", Dereference: true}}, + {&FSBind{Source: fhs.AbsVarLib.Append("hakurei/u0/org.chromium.Chromium"), Target: check.MustAbs("/data/data/org.chromium.Chromium"), Write: true, Ensure: true}}, - {&FSBind{Source: container.AbsFHSDev.Append("dri"), Device: true, Optional: true}}, + {&FSBind{Source: fhs.AbsDev.Append("dri"), Device: true, Optional: true}}, }, Username: "chronos", - Shell: container.AbsFHSRun.Append("current-system/sw/bin/zsh"), + Shell: fhs.AbsRun.Append("current-system/sw/bin/zsh"), Home: check.MustAbs("/data/data/org.chromium.Chromium"), - Path: container.AbsFHSRun.Append("current-system/sw/bin/chromium"), + Path: fhs.AbsRun.Append("current-system/sw/bin/chromium"), Args: []string{ "chromium", "--ignore-gpu-blocklist", diff --git a/internal/app/app_test.go b/internal/app/app_test.go index 851d7c2..e0f9305 100644 --- a/internal/app/app_test.go +++ b/internal/app/app_test.go @@ -17,6 +17,7 @@ import ( "hakurei.app/container" "hakurei.app/container/bits" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/hst" "hakurei.app/internal/app/state" "hakurei.app/system" @@ -42,19 +43,19 @@ func TestApp(t *testing.T) { Filesystem: []hst.FilesystemConfigJSON{ {FilesystemConfig: &hst.FSBind{ - Target: container.AbsFHSRoot, - Source: container.AbsFHSRoot, + Target: fhs.AbsRoot, + Source: fhs.AbsRoot, Write: true, Special: true, }}, {FilesystemConfig: &hst.FSBind{ - Source: container.AbsFHSDev.Append("kvm"), + Source: fhs.AbsDev.Append("kvm"), Device: true, Optional: true, }}, {FilesystemConfig: &hst.FSBind{ - Target: container.AbsFHSEtc, - Source: container.AbsFHSEtc, + Target: fhs.AbsEtc, + Source: fhs.AbsEtc, Special: true, }}, }, @@ -160,24 +161,24 @@ func TestApp(t *testing.T) { Filesystem: []hst.FilesystemConfigJSON{ {FilesystemConfig: &hst.FSBind{ - Target: container.AbsFHSRoot, - Source: container.AbsFHSRoot, + Target: fhs.AbsRoot, + Source: fhs.AbsRoot, Write: true, Special: true, }}, {FilesystemConfig: &hst.FSBind{ - Source: container.AbsFHSDev.Append("dri"), + Source: fhs.AbsDev.Append("dri"), Device: true, Optional: true, }}, {FilesystemConfig: &hst.FSBind{ - Source: container.AbsFHSDev.Append("kvm"), + Source: fhs.AbsDev.Append("kvm"), Device: true, Optional: true, }}, {FilesystemConfig: &hst.FSBind{ - Target: container.AbsFHSEtc, - Source: container.AbsFHSEtc, + Target: fhs.AbsEtc, + Source: fhs.AbsEtc, Special: true, }}, }, diff --git a/internal/app/env_test.go b/internal/app/env_test.go index cf6a18b..b28c156 100644 --- a/internal/app/env_test.go +++ b/internal/app/env_test.go @@ -7,6 +7,7 @@ import ( "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/container/stub" "hakurei.app/hst" ) @@ -23,26 +24,26 @@ func TestEnvPaths(t *testing.T) { {"zero", new(EnvPaths), hst.Paths{}, "attempting to use an invalid EnvPaths"}, {"nil tempdir", &EnvPaths{ - RuntimePath: container.AbsFHSTmp, + RuntimePath: fhs.AbsTmp, }, hst.Paths{}, "attempting to use an invalid EnvPaths"}, {"nil runtime", &EnvPaths{ - TempDir: container.AbsFHSTmp, + TempDir: fhs.AbsTmp, }, hst.Paths{ - TempDir: container.AbsFHSTmp, - SharePath: container.AbsFHSTmp.Append("hakurei.3735928559"), - RuntimePath: container.AbsFHSTmp.Append("hakurei.3735928559/run/compat"), - RunDirPath: container.AbsFHSTmp.Append("hakurei.3735928559/run"), + TempDir: fhs.AbsTmp, + SharePath: fhs.AbsTmp.Append("hakurei.3735928559"), + RuntimePath: fhs.AbsTmp.Append("hakurei.3735928559/run/compat"), + RunDirPath: fhs.AbsTmp.Append("hakurei.3735928559/run"), }, ""}, {"full", &EnvPaths{ - TempDir: container.AbsFHSTmp, - RuntimePath: container.AbsFHSRunUser.Append("1000"), + TempDir: fhs.AbsTmp, + RuntimePath: fhs.AbsRunUser.Append("1000"), }, hst.Paths{ - TempDir: container.AbsFHSTmp, - SharePath: container.AbsFHSTmp.Append("hakurei.3735928559"), - RuntimePath: container.AbsFHSRunUser.Append("1000"), - RunDirPath: container.AbsFHSRunUser.Append("1000/hakurei"), + TempDir: fhs.AbsTmp, + SharePath: fhs.AbsTmp.Append("hakurei.3735928559"), + RuntimePath: fhs.AbsRunUser.Append("1000"), + RunDirPath: fhs.AbsRunUser.Append("1000/hakurei"), }, ""}, } for _, tc := range testCases { diff --git a/internal/app/finalise.go b/internal/app/finalise.go index 2fa4ca0..f544ebe 100644 --- a/internal/app/finalise.go +++ b/internal/app/finalise.go @@ -16,6 +16,7 @@ import ( "syscall" "hakurei.app/container" + "hakurei.app/container/fhs" "hakurei.app/hst" "hakurei.app/internal/app/state" "hakurei.app/system" @@ -184,7 +185,7 @@ func (k *outcome) finalise(ctx context.Context, msg container.Msg, id *state.ID, // mount root read-only as the final setup Op // TODO(ophestra): move this to spFilesystemOp after #8 and #9 - k.container.Remount(container.AbsFHSRoot, syscall.MS_RDONLY) + k.container.Remount(fhs.AbsRoot, syscall.MS_RDONLY) // append ExtraPerms last for _, p := range config.ExtraPerms { diff --git a/internal/app/hsu.go b/internal/app/hsu.go index 93b6bb8..982cb51 100644 --- a/internal/app/hsu.go +++ b/internal/app/hsu.go @@ -10,6 +10,7 @@ import ( "sync" "hakurei.app/container" + "hakurei.app/container/fhs" "hakurei.app/hst" ) @@ -45,7 +46,7 @@ func (h *Hsu) ID() (int, error) { cmd.Path = hsuPath cmd.Stderr = os.Stderr // pass through fatal messages cmd.Env = make([]string, 0) - cmd.Dir = container.FHSRoot + cmd.Dir = fhs.Root var ( p []byte exitError *exec.ExitError diff --git a/internal/app/process.go b/internal/app/process.go index 80a256c..1e738e7 100644 --- a/internal/app/process.go +++ b/internal/app/process.go @@ -14,6 +14,7 @@ import ( "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/hst" "hakurei.app/internal" "hakurei.app/internal/app/state" @@ -253,7 +254,7 @@ func (k *outcome) main(msg container.Msg) { ms.cmd = exec.CommandContext(ctx, hsuPath.String()) ms.cmd.Stdin, ms.cmd.Stdout, ms.cmd.Stderr = os.Stdin, os.Stdout, os.Stderr - ms.cmd.Dir = container.FHSRoot // container init enters final working directory + ms.cmd.Dir = fhs.Root // container init enters final working directory // shim runs in the same session as monitor; see shim.go for behaviour ms.cmd.Cancel = func() error { return ms.cmd.Process.Signal(syscall.SIGCONT) } diff --git a/internal/app/spaccount.go b/internal/app/spaccount.go index 71c7d7f..0927bcc 100644 --- a/internal/app/spaccount.go +++ b/internal/app/spaccount.go @@ -4,7 +4,7 @@ import ( "fmt" "syscall" - "hakurei.app/container" + "hakurei.app/container/fhs" "hakurei.app/hst" ) @@ -34,14 +34,14 @@ func (s spAccountOp) toContainer(state *outcomeStateParams) error { state.env["SHELL"] = state.Container.Shell.String() state.params. - Place(container.AbsFHSEtc.Append("passwd"), + Place(fhs.AbsEtc.Append("passwd"), []byte(state.Container.Username+":x:"+ state.mapuid.String()+":"+ state.mapgid.String()+ ":Hakurei:"+ state.Container.Home.String()+":"+ state.Container.Shell.String()+"\n")). - Place(container.AbsFHSEtc.Append("group"), + Place(fhs.AbsEtc.Append("group"), []byte("hakurei:x:"+state.mapgid.String()+":\n")) return nil diff --git a/internal/app/spcontainer.go b/internal/app/spcontainer.go index 6dd2bca..aed6d92 100644 --- a/internal/app/spcontainer.go +++ b/internal/app/spcontainer.go @@ -10,12 +10,13 @@ import ( "hakurei.app/container" "hakurei.app/container/bits" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/container/seccomp" "hakurei.app/hst" "hakurei.app/system/dbus" ) -const varRunNscd = container.FHSVar + "run/nscd" +const varRunNscd = fhs.Var + "run/nscd" // spParamsOp initialises unordered fields of [container.Params] and the optional root filesystem. // This outcomeOp is hardcoded to always run first. @@ -98,15 +99,15 @@ func (s *spParamsOp) toContainer(state *outcomeStateParams) error { // early mount points state.params. - Proc(container.AbsFHSProc). + Proc(fhs.AbsProc). Tmpfs(hst.AbsTmp, 1<<12, 0755) if !state.Container.Device { - state.params.DevWritable(container.AbsFHSDev, true) + state.params.DevWritable(fhs.AbsDev, true) } else { - state.params.Bind(container.AbsFHSDev, container.AbsFHSDev, container.BindWritable|container.BindDevice) + state.params.Bind(fhs.AbsDev, fhs.AbsDev, container.BindWritable|container.BindDevice) } // /dev is mounted readonly later on, this prevents /dev/shm from going readonly with it - state.params.Tmpfs(container.AbsFHSDev.Append("shm"), 0, 01777) + state.params.Tmpfs(fhs.AbsDev.Append("shm"), 0, 01777) return nil } @@ -142,7 +143,7 @@ func (s spFilesystemOp) toSystem(state *outcomeStateSys, _ *hst.Config) error { if path.IsAbs(pair[1]) { // get parent dir of socket dir := path.Dir(pair[1]) - if dir == "." || dir == container.FHSRoot { + if dir == "." || dir == fhs.Root { state.msg.Verbosef("dbus socket %q is in an unusual location", pair[1]) } hidePaths = append(hidePaths, dir) @@ -267,7 +268,7 @@ func (s spFilesystemOp) toContainer(state *outcomeStateParams) error { // no more configured paths beyond this point if !state.Container.Device { - state.params.Remount(container.AbsFHSDev, syscall.MS_RDONLY) + state.params.Remount(fhs.AbsDev, syscall.MS_RDONLY) } return nil } @@ -278,7 +279,7 @@ func resolveRoot(c *hst.ContainerConfig) (rootfs hst.FilesystemConfig, filesyste // root filesystem special case filesystem = c.Filesystem // valid happens late, so root gets it here - if len(filesystem) > 0 && filesystem[0].Valid() && filesystem[0].Path().String() == container.FHSRoot { + if len(filesystem) > 0 && filesystem[0].Valid() && filesystem[0].Path().String() == fhs.Root { // if the first element targets /, it is inserted early and excluded from path hiding rootfs = filesystem[0].FilesystemConfig filesystem = filesystem[1:] diff --git a/internal/app/spdbus.go b/internal/app/spdbus.go index 42d523d..77c2dcd 100644 --- a/internal/app/spdbus.go +++ b/internal/app/spdbus.go @@ -1,7 +1,7 @@ package app import ( - "hakurei.app/container" + "hakurei.app/container/fhs" "hakurei.app/hst" "hakurei.app/system/acl" "hakurei.app/system/dbus" @@ -42,7 +42,7 @@ func (s *spDBusOp) toContainer(state *outcomeStateParams) error { state.env["DBUS_SESSION_BUS_ADDRESS"] = "unix:path=" + sessionInner.String() state.params.Bind(state.instancePath().Append("bus"), sessionInner, 0) if s.ProxySystem { - systemInner := container.AbsFHSRun.Append("dbus/system_bus_socket") + systemInner := fhs.AbsRun.Append("dbus/system_bus_socket") state.env["DBUS_SYSTEM_BUS_ADDRESS"] = "unix:path=" + systemInner.String() state.params.Bind(state.instancePath().Append("system_bus_socket"), systemInner, 0) } diff --git a/internal/app/spruntime.go b/internal/app/spruntime.go index 0559718..be18885 100644 --- a/internal/app/spruntime.go +++ b/internal/app/spruntime.go @@ -3,6 +3,7 @@ package app import ( "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/hst" "hakurei.app/system" "hakurei.app/system/acl" @@ -27,13 +28,13 @@ func (s spRuntimeOp) toContainer(state *outcomeStateParams) error { xdgSessionType = "XDG_SESSION_TYPE" ) - state.runtimeDir = container.AbsFHSRunUser.Append(state.mapuid.String()) + state.runtimeDir = fhs.AbsRunUser.Append(state.mapuid.String()) state.env[xdgRuntimeDir] = state.runtimeDir.String() state.env[xdgSessionClass] = "user" state.env[xdgSessionType] = "tty" _, runtimeDirInst := s.commonPaths(state.outcomeState) - state.params.Tmpfs(container.AbsFHSRunUser, 1<<12, 0755) + state.params.Tmpfs(fhs.AbsRunUser, 1<<12, 0755) state.params.Bind(runtimeDirInst, state.runtimeDir, container.BindWritable) return nil } diff --git a/internal/app/sptmpdir.go b/internal/app/sptmpdir.go index 0e5cfe9..265e51c 100644 --- a/internal/app/sptmpdir.go +++ b/internal/app/sptmpdir.go @@ -3,6 +3,7 @@ package app import ( "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/hst" "hakurei.app/system" "hakurei.app/system/acl" @@ -23,7 +24,7 @@ func (s spTmpdirOp) toSystem(state *outcomeStateSys, _ *hst.Config) error { func (s spTmpdirOp) toContainer(state *outcomeStateParams) error { // mount inner /tmp from share so it shares persistence and storage behaviour of host /tmp _, tmpdirInst := s.commonPaths(state.outcomeState) - state.params.Bind(tmpdirInst, container.AbsFHSTmp, container.BindWritable) + state.params.Bind(tmpdirInst, fhs.AbsTmp, container.BindWritable) return nil } diff --git a/internal/app/spx11.go b/internal/app/spx11.go index b21eb48..18890fd 100644 --- a/internal/app/spx11.go +++ b/internal/app/spx11.go @@ -7,13 +7,13 @@ import ( "strconv" "strings" - "hakurei.app/container" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/hst" "hakurei.app/system/acl" ) -var absX11SocketDir = container.AbsFHSTmp.Append(".X11-unix") +var absX11SocketDir = fhs.AbsTmp.Append(".X11-unix") // spX11Op exports the X11 display server to the container. type spX11Op struct { diff --git a/ldd/exec.go b/ldd/exec.go index 77b46de..5554d9b 100644 --- a/ldd/exec.go +++ b/ldd/exec.go @@ -11,6 +11,7 @@ import ( "hakurei.app/container" "hakurei.app/container/bits" "hakurei.app/container/check" + "hakurei.app/container/fhs" "hakurei.app/container/seccomp" ) @@ -43,9 +44,9 @@ func Exec(ctx context.Context, msg container.Msg, p string) ([]*Entry, error) { z.Stdout = stdout z.Stderr = stderr z. - Bind(container.AbsFHSRoot, container.AbsFHSRoot, 0). - Proc(container.AbsFHSProc). - Dev(container.AbsFHSDev, false) + Bind(fhs.AbsRoot, fhs.AbsRoot, 0). + Proc(fhs.AbsProc). + Dev(fhs.AbsDev, false) if err := z.Start(); err != nil { return nil, err