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
The memory saving is relatively insignificant, however this increases serialisation efficiency. Signed-off-by: Ophestra <cat@gensokyo.uk>
190 lines
5.5 KiB
Go
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
|
|
}
|