container/fhs: move pathname constants
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 2m6s
Test / Hpkg (push) Successful in 4m1s
Test / Sandbox (race detector) (push) Successful in 4m29s
Test / Hakurei (race detector) (push) Successful in 3m5s
Test / Hakurei (push) Successful in 2m10s
Test / Flake checks (push) Successful in 1m21s

This allows referencing FHS pathnames without importing container.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-10-07 21:29:16 +09:00
parent 0e6c1a5026
commit 5d18af0007
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
33 changed files with 264 additions and 233 deletions

View File

@ -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,
}},
)

View File

@ -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}},
},

View File

@ -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

View File

@ -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}},
}...)
}

View File

@ -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}},
},

View File

@ -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 {

View File

@ -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 {

View File

@ -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)

41
container/fhs/abs.go Normal file
View File

@ -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)
)

38
container/fhs/fhs.go Normal file
View File

@ -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/"
)

View File

@ -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)
}

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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

View File

@ -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.

View File

@ -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"
)

View File

@ -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) {

View File

@ -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)
})
})

View File

@ -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, "<invalid>"},
{"nil path", &hst.ExtraPermConfig{Path: nil}, "<invalid>"},
{"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 {

View File

@ -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

View File

@ -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",

View File

@ -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,
}},
},

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -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) }

View File

@ -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

View File

@ -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:]

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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