hakurei/hst/container.go
Ophestra 4c647add0d
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m12s
Test / Hakurei (push) Successful in 3m8s
Test / Hpkg (push) Successful in 4m2s
Test / Hakurei (race detector) (push) Successful in 4m46s
Test / Sandbox (race detector) (push) Successful in 2m11s
Test / Flake checks (push) Successful in 1m37s
hst/container: pack boolean options
The memory saving is relatively insignificant, however this increases serialisation efficiency.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2025-10-14 06:39:00 +09:00

190 lines
5.5 KiB
Go

package hst
import (
"encoding/json"
"syscall"
"time"
"hakurei.app/container/check"
)
// PrivateTmp is a private writable path in a hakurei container.
const PrivateTmp = "/.hakurei"
// AbsPrivateTmp is a [check.Absolute] representation of [PrivateTmp].
var AbsPrivateTmp = check.MustAbs(PrivateTmp)
const (
// WaitDelayDefault is used when WaitDelay has its zero value.
WaitDelayDefault = 5 * time.Second
// WaitDelayMax is used if WaitDelay exceeds its value.
WaitDelayMax = 30 * time.Second
// IdentityMin is the minimum value of [Config.Identity]. This is enforced by cmd/hsu.
IdentityMin = 0
// IdentityMax is the maximum value of [Config.Identity]. This is enforced by cmd/hsu.
IdentityMax = 9999
// ShimExitRequest is returned when the priv side process requests shim exit.
ShimExitRequest = 254
// ShimExitOrphan is returned when the shim is orphaned before priv side delivers a signal.
ShimExitOrphan = 3
)
const (
// FMultiarch unblocks syscalls required for multiarch to work on applicable targets.
FMultiarch uintptr = 1 << iota
// FSeccompCompat causes emitted seccomp filter programs to be identical to Flatpak.
FSeccompCompat
// FDevel unblocks ptrace and friends.
FDevel
// FUserns unblocks userns creation and container setup syscalls.
FUserns
// FHostNet skips net namespace creation.
FHostNet
// FHostAbstract skips setting up abstract unix socket scope.
FHostAbstract
// FTty unblocks dangerous terminal I/O (faking input).
FTty
// FMapRealUID maps the target user uid to the privileged user uid in the container user namespace.
// Some programs fail to connect to dbus session running as a different uid,
// this option works around it by mapping priv-side caller uid in container.
FMapRealUID
// FDevice mount /dev/ from the init mount namespace as-is in the container mount namespace.
FDevice
fMax
// FAll is [ContainerConfig.Flags] with all currently defined bits set.
FAll = fMax - 1
)
// ContainerConfig describes the container configuration to be applied to an underlying [container].
type ContainerConfig struct {
// Container UTS namespace hostname.
Hostname string `json:"hostname,omitempty"`
// Duration in nanoseconds to wait for after interrupting the initial process.
// Defaults to [WaitDelayDefault] if zero, or [WaitDelayMax] if greater than [WaitDelayMax].
// Values lesser than zero is equivalent to zero, bypassing [WaitDelayDefault].
WaitDelay time.Duration `json:"wait_delay,omitempty"`
// Initial process environment variables.
Env map[string]string `json:"env"`
/* Container mount points.
If the first element targets /, it is inserted early and excluded from path hiding. */
Filesystem []FilesystemConfigJSON `json:"filesystem"`
// String used as the username of the emulated user, validated against the default NAME_REGEX from adduser.
// Defaults to passwd name of target uid or chronos.
Username string `json:"username,omitempty"`
// Pathname of shell in the container filesystem to use for the emulated user.
Shell *check.Absolute `json:"shell"`
// Directory in the container filesystem to enter and use as the home directory of the emulated user.
Home *check.Absolute `json:"home"`
// Pathname to executable file in the container filesystem.
Path *check.Absolute `json:"path,omitempty"`
// Final args passed to the initial program.
Args []string `json:"args"`
// Flags holds boolean options of [ContainerConfig].
Flags uintptr `json:"-"`
}
// ContainerConfigF is [ContainerConfig] stripped of its methods.
// The [ContainerConfig.Flags] field does not survive a [json] round trip.
type ContainerConfigF ContainerConfig
// containerConfigJSON is the [json] representation of [ContainerConfig].
type containerConfigJSON = struct {
*ContainerConfigF
// Corresponds to [FSeccompCompat].
SeccompCompat bool `json:"seccomp_compat,omitempty"`
// Corresponds to [FDevel].
Devel bool `json:"devel,omitempty"`
// Corresponds to [FUserns].
Userns bool `json:"userns,omitempty"`
// Corresponds to [FHostNet].
HostNet bool `json:"host_net,omitempty"`
// Corresponds to [FHostAbstract].
HostAbstract bool `json:"host_abstract,omitempty"`
// Corresponds to [FTty].
Tty bool `json:"tty,omitempty"`
// Corresponds to [FMultiarch].
Multiarch bool `json:"multiarch,omitempty"`
// Corresponds to [FMapRealUID].
MapRealUID bool `json:"map_real_uid"`
// Corresponds to [FDevice].
Device bool `json:"device,omitempty"`
}
func (c *ContainerConfig) MarshalJSON() ([]byte, error) {
if c == nil {
return nil, syscall.EINVAL
}
return json.Marshal(&containerConfigJSON{
ContainerConfigF: (*ContainerConfigF)(c),
SeccompCompat: c.Flags&FSeccompCompat != 0,
Devel: c.Flags&FDevel != 0,
Userns: c.Flags&FUserns != 0,
HostNet: c.Flags&FHostNet != 0,
HostAbstract: c.Flags&FHostAbstract != 0,
Tty: c.Flags&FTty != 0,
Multiarch: c.Flags&FMultiarch != 0,
MapRealUID: c.Flags&FMapRealUID != 0,
Device: c.Flags&FDevice != 0,
})
}
func (c *ContainerConfig) UnmarshalJSON(data []byte) error {
if c == nil {
return syscall.EINVAL
}
v := new(containerConfigJSON)
if err := json.Unmarshal(data, &v); err != nil {
return err
}
*c = *(*ContainerConfig)(v.ContainerConfigF)
if v.SeccompCompat {
c.Flags |= FSeccompCompat
}
if v.Devel {
c.Flags |= FDevel
}
if v.Userns {
c.Flags |= FUserns
}
if v.HostNet {
c.Flags |= FHostNet
}
if v.HostAbstract {
c.Flags |= FHostAbstract
}
if v.Tty {
c.Flags |= FTty
}
if v.Multiarch {
c.Flags |= FMultiarch
}
if v.MapRealUID {
c.Flags |= FMapRealUID
}
if v.Device {
c.Flags |= FDevice
}
return nil
}