hst: improve doc comments
All checks were successful
Test / Create distribution (push) Successful in 1m3s
Test / Sandbox (push) Successful in 2m40s
Test / Hakurei (push) Successful in 3m40s
Test / ShareFS (push) Successful in 3m47s
Test / Sandbox (race detector) (push) Successful in 5m3s
Test / Hakurei (race detector) (push) Successful in 5m58s
Test / Flake checks (push) Successful in 1m26s

These now read a lot better both in source and on pkgsite.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2026-03-11 19:21:55 +09:00
parent 48cdf8bf85
commit 330a344845
9 changed files with 212 additions and 115 deletions

View File

@@ -8,74 +8,97 @@ import (
"hakurei.app/container/check"
)
// Config configures an application container, implemented in internal/app.
// Config configures an application container.
type Config struct {
// Reverse-DNS style configured arbitrary identifier string.
// Passed to wayland security-context-v1 and used as part of defaults in dbus session proxy.
//
// This value is passed as is to Wayland security-context-v1 and used as
// part of defaults in D-Bus session proxy. The zero value causes a default
// value to be derived from the container instance.
ID string `json:"id,omitempty"`
// System services to make available in the container.
Enablements *Enablements `json:"enablements,omitempty"`
// Session D-Bus proxy configuration.
// If set to nil, session bus proxy assume built-in defaults.
//
// Has no effect if [EDBus] but is not set in Enablements. The zero value
// assumes built-in defaults derived from ID.
SessionBus *BusConfig `json:"session_bus,omitempty"`
// System D-Bus proxy configuration.
// If set to nil, system bus proxy is disabled.
//
// Has no effect if [EDBus] but is not set in Enablements. The zero value
// disables system bus proxy.
SystemBus *BusConfig `json:"system_bus,omitempty"`
// Direct access to wayland socket, no attempt is made to attach security-context-v1
// and the bare socket is made available to the container.
// Direct access to Wayland socket, no attempt is made to attach
// security-context-v1 and the bare socket is made available to the
// container.
//
// This option is unsupported and most likely enables full control over the Wayland
// session. Do not set this to true unless you are sure you know what you are doing.
// This option is unsupported and will most likely enable full control over
// the Wayland session from within the container. Do not set this to true
// unless you are sure you know what you are doing.
DirectWayland bool `json:"direct_wayland,omitempty"`
// Direct access to the PipeWire socket established via SecurityContext::Create, no
// attempt is made to start the pipewire-pulse server.
// Direct access to the PipeWire socket established via SecurityContext::Create,
// no attempt is made to start the pipewire-pulse server.
//
// The SecurityContext machinery is fatally flawed, it blindly sets read and execute
// bits on all objects for clients with the lowest achievable privilege level (by
// setting PW_KEY_ACCESS to "restricted"). This enables them to call any method
// targeting any object, and since Registry::Destroy checks for the read and execute bit,
// allows the destruction of any object other than PW_ID_CORE as well. This behaviour
// is implemented separately in media-session and wireplumber, with the wireplumber
// implementation in Lua via an embedded Lua vm. In all known setups, wireplumber is
// in use, and there is no known way to change its behaviour and set permissions
// differently without replacing the Lua script. Also, since PipeWire relies on these
// permissions to work, reducing them is not possible.
// The SecurityContext machinery is fatally flawed, it unconditionally sets
// read and execute bits on all objects for clients with the lowest achievable
// privilege level (by setting PW_KEY_ACCESS to "restricted" or by satisfying
// all conditions of [the /.flatpak-info hack]). This enables them to call
// any method targeting any object, and since Registry::Destroy checks for
// the read and execute bit, allows the destruction of any object other than
// PW_ID_CORE as well.
//
// Currently, the only other sandboxed use case is flatpak, which is not aware of
// PipeWire and blindly exposes the bare PulseAudio socket to the container (behaves
// like DirectPulse). This socket is backed by the pipewire-pulse compatibility daemon,
// which obtains client pid via the SO_PEERCRED option. The PipeWire daemon, pipewire-pulse
// daemon and the session manager daemon then separately performs the /.flatpak-info hack
// described in https://git.gensokyo.uk/security/hakurei/issues/21. Under such use case,
// since the client has no direct access to PipeWire, insecure parts of the protocol are
// obscured by pipewire-pulse simply not implementing them, and thus hiding the flaws
// described above.
// This behaviour is implemented separately in media-session and wireplumber,
// with the wireplumber implementation in Lua via an embedded Lua vm. In all
// known setups, wireplumber is in use, and in that case, no option for
// configuring this behaviour exists, without replacing the Lua script.
// Also, since PipeWire relies on these permissions to work, reducing them
// was never possible in the first place.
//
// Hakurei does not rely on the /.flatpak-info hack. Instead, a socket is sets up via
// SecurityContext. A pipewire-pulse server connected through it achieves the same
// permissions as flatpak does via the /.flatpak-info hack and is maintained for the
// life of the container.
// Currently, the only other sandboxed use case is flatpak, which is not
// aware of PipeWire and blindly exposes the bare PulseAudio socket to the
// container (behaves like DirectPulse). This socket is backed by the
// pipewire-pulse compatibility daemon, which obtains client pid via the
// SO_PEERCRED option. The PipeWire daemon, pipewire-pulse daemon and the
// session manager daemon then separately performs [the /.flatpak-info hack].
// Under such use case, since the client has no direct access to PipeWire,
// insecure parts of the protocol are obscured by the absence of an
// equivalent API in PulseAudio, or pipewire-pulse simply not implementing
// them.
//
// Hakurei does not rely on [the /.flatpak-info hack]. Instead, a socket is
// sets up via SecurityContext. A pipewire-pulse server connected through it
// achieves the same permissions as flatpak does via [the /.flatpak-info hack]
// and is maintained for the life of the container.
//
// This option is unsupported and enables a denial-of-service attack as the
// sandboxed client is able to destroy any client object and thus
// disconnecting them from PipeWire, or destroy the SecurityContext object,
// preventing any further container creation.
//
// This option is unsupported and enables a denial-of-service attack as the sandboxed
// client is able to destroy any client object and thus disconnecting them from PipeWire,
// or destroy the SecurityContext object preventing any further container creation.
// Do not set this to true, it is insecure under any configuration.
DirectPipeWire bool `json:"direct_pipewire,omitempty"`
// Direct access to PulseAudio socket, no attempt is made to establish pipewire-pulse
// server via a PipeWire socket with a SecurityContext attached and the bare socket
// is made available to the container.
//
// This option is unsupported and enables arbitrary code execution as the PulseAudio
// server. Do not set this to true, it is insecure under any configuration.
// [the /.flatpak-info hack]: https://git.gensokyo.uk/security/hakurei/issues/21
DirectPipeWire bool `json:"direct_pipewire,omitempty"`
// Direct access to PulseAudio socket, no attempt is made to establish
// pipewire-pulse server via a PipeWire socket with a SecurityContext
// attached, and the bare socket is made available to the container.
//
// This option is unsupported and enables arbitrary code execution as the
// PulseAudio server.
//
// Do not set this to true, it is insecure under any configuration.
DirectPulse bool `json:"direct_pulse,omitempty"`
// Extra acl updates to perform before setuid.
ExtraPerms []ExtraPermConfig `json:"extra_perms,omitempty"`
// Numerical application id, passed to hsu, used to derive init user namespace credentials.
// Numerical application id, passed to hsu, used to derive init user
// namespace credentials.
Identity int `json:"identity"`
// Init user namespace supplementary groups inherited by all container processes.
Groups []string `json:"groups"`
@@ -85,17 +108,20 @@ type Config struct {
}
var (
// ErrConfigNull is returned by [Config.Validate] for an invalid configuration that contains a null value for any
// field that must not be null.
// ErrConfigNull is returned by [Config.Validate] for an invalid configuration
// that contains a null value for any field that must not be null.
ErrConfigNull = errors.New("unexpected null in config")
// ErrIdentityBounds is returned by [Config.Validate] for an out of bounds [Config.Identity] value.
// ErrIdentityBounds is returned by [Config.Validate] for an out of bounds
// [Config.Identity] value.
ErrIdentityBounds = errors.New("identity out of bounds")
// ErrEnviron is returned by [Config.Validate] if an environment variable name contains '=' or NUL.
// ErrEnviron is returned by [Config.Validate] if an environment variable
// name contains '=' or NUL.
ErrEnviron = errors.New("invalid environment variable name")
// ErrInsecure is returned by [Config.Validate] if the configuration is considered insecure.
// ErrInsecure is returned by [Config.Validate] if the configuration is
// considered insecure.
ErrInsecure = errors.New("configuration is insecure")
)