diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-10-07 21:29:16 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-10-07 21:29:16 +0900 |
| commit | 5d18af00077ae6ba8ef686d1fd93d888f69681b2 (patch) | |
| tree | eff32422fe3ef095c6a915ccb41c2a10a06990f7 /container | |
| parent | 0e6c1a50260de141c50bb50fd3f2b2bcf9a3fe64 (diff) | |
container/fhs: move pathname constants
This allows referencing FHS pathnames without importing container.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'container')
| -rw-r--r-- | container/autoetc.go | 9 | ||||
| -rw-r--r-- | container/autoroot.go | 3 | ||||
| -rw-r--r-- | container/container.go | 5 | ||||
| -rw-r--r-- | container/fhs/abs.go | 41 | ||||
| -rw-r--r-- | container/fhs/fhs.go | 38 | ||||
| -rw-r--r-- | container/init.go | 17 | ||||
| -rw-r--r-- | container/initdev.go | 9 | ||||
| -rw-r--r-- | container/initoverlay.go | 11 | ||||
| -rw-r--r-- | container/initplace.go | 3 | ||||
| -rw-r--r-- | container/mount.go | 1 | ||||
| -rw-r--r-- | container/path.go | 79 | ||||
| -rw-r--r-- | container/sysctl.go | 8 |
12 files changed, 120 insertions, 104 deletions
diff --git a/container/autoetc.go b/container/autoetc.go index 295bdf71..65ab9a2c 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 519aadaf..0ebe6b2b 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 08dc9e45..5b6514d4 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 00000000..af3588ba --- /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 00000000..6a3a3041 --- /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 e65472e7..9481acd1 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 e7c4eabf..89a66138 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 74d925a7..74ae7d00 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 1f41846b..d08cf653 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 dbd39cb9..2749d0ec 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 bf3f870d..bc0000ad 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 327872b5..9a1e818e 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) { |
