hst: add pipewire flag
All checks were successful
Test / Create distribution (push) Successful in 36s
Test / Sandbox (push) Successful in 2m36s
Test / Sandbox (race detector) (push) Successful in 4m47s
Test / Hpkg (push) Successful in 4m55s
Test / Hakurei (push) Successful in 4m59s
Test / Hakurei (race detector) (push) Successful in 6m26s
Test / Flake checks (push) Successful in 1m31s

These are for #26. None of them are implemented yet. This fixes up test cases for the change to happen. Existing source code and JSON configuration continue to have the same effect. Existing flags get its EPulse bit replaced by EPipeWire.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-12-07 22:33:45 +09:00
parent 093e30c788
commit 1931b54600
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
9 changed files with 47 additions and 18 deletions

View File

@ -32,7 +32,7 @@ var (
PID: 0xbeef, PID: 0xbeef,
ShimPID: 0xcafe, ShimPID: 0xcafe,
Config: &hst.Config{ Config: &hst.Config{
Enablements: hst.NewEnablements(hst.EWayland | hst.EPulse), Enablements: hst.NewEnablements(hst.EWayland | hst.EPipeWire),
Identity: 1, Identity: 1,
Container: &hst.ContainerConfig{ Container: &hst.ContainerConfig{
Shell: check.MustAbs("/bin/sh"), Shell: check.MustAbs("/bin/sh"),
@ -62,7 +62,7 @@ func TestPrintShowInstance(t *testing.T) {
{"nil", nil, nil, false, false, "Error: invalid configuration!\n\n", false}, {"nil", nil, nil, false, false, "Error: invalid configuration!\n\n", false},
{"config", nil, hst.Template(), false, false, `App {"config", nil, hst.Template(), false, false, `App
Identity: 9 (org.chromium.Chromium) Identity: 9 (org.chromium.Chromium)
Enablements: wayland, dbus, pulseaudio Enablements: wayland, dbus, pipewire, pulseaudio
Groups: video, dialout, plugdev Groups: video, dialout, plugdev
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir
Home: /data/data/org.chromium.Chromium Home: /data/data/org.chromium.Chromium
@ -159,7 +159,7 @@ Session bus
App App
Identity: 9 (org.chromium.Chromium) Identity: 9 (org.chromium.Chromium)
Enablements: wayland, dbus, pulseaudio Enablements: wayland, dbus, pipewire, pulseaudio
Groups: video, dialout, plugdev Groups: video, dialout, plugdev
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir
Home: /data/data/org.chromium.Chromium Home: /data/data/org.chromium.Chromium
@ -215,6 +215,7 @@ App
"enablements": { "enablements": {
"wayland": true, "wayland": true,
"dbus": true, "dbus": true,
"pipewire": true,
"pulse": true "pulse": true
}, },
"session_bus": { "session_bus": {
@ -366,6 +367,7 @@ App
"enablements": { "enablements": {
"wayland": true, "wayland": true,
"dbus": true, "dbus": true,
"pipewire": true,
"pulse": true "pulse": true
}, },
"session_bus": { "session_bus": {
@ -564,6 +566,7 @@ func TestPrintPs(t *testing.T) {
"enablements": { "enablements": {
"wayland": true, "wayland": true,
"dbus": true, "dbus": true,
"pipewire": true,
"pulse": true "pulse": true
}, },
"session_bus": { "session_bus": {
@ -715,7 +718,7 @@ func TestPrintPs(t *testing.T) {
"shim_pid": 51966, "shim_pid": 51966,
"enablements": { "enablements": {
"wayland": true, "wayland": true,
"pulse": true "pipewire": true
}, },
"identity": 1, "identity": 1,
"groups": null, "groups": null,

View File

@ -23,9 +23,20 @@ type Config struct {
// System D-Bus proxy configuration. // System D-Bus proxy configuration.
// If set to nil, system bus proxy is disabled. // If set to nil, system bus proxy is disabled.
SystemBus *BusConfig `json:"system_bus,omitempty"` SystemBus *BusConfig `json:"system_bus,omitempty"`
// Direct access to wayland socket, no attempt is made to attach security-context-v1 // Direct access to wayland socket, no attempt is made to attach security-context-v1
// and the bare socket is made available to the container. // 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.
DirectWayland bool `json:"direct_wayland,omitempty"` DirectWayland bool `json:"direct_wayland,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, this is insecure under any configuration.
DirectPulse bool `json:"direct_pulse,omitempty"`
// Extra acl updates to perform before setuid. // Extra acl updates to perform before setuid.
ExtraPerms []ExtraPermConfig `json:"extra_perms,omitempty"` ExtraPerms []ExtraPermConfig `json:"extra_perms,omitempty"`

View File

@ -17,6 +17,8 @@ const (
EX11 EX11
// EDBus enables the per-container xdg-dbus-proxy daemon. // EDBus enables the per-container xdg-dbus-proxy daemon.
EDBus EDBus
// EPipeWire exposes a pipewire pathname socket via SecurityContext.
EPipeWire
// EPulse copies the PulseAudio cookie to [hst.PrivateTmp] and exposes the PulseAudio socket. // EPulse copies the PulseAudio cookie to [hst.PrivateTmp] and exposes the PulseAudio socket.
EPulse EPulse
@ -35,6 +37,8 @@ func (e Enablement) String() string {
return "x11" return "x11"
case EDBus: case EDBus:
return "dbus" return "dbus"
case EPipeWire:
return "pipewire"
case EPulse: case EPulse:
return "pulseaudio" return "pulseaudio"
default: default:
@ -62,10 +66,11 @@ type Enablements Enablement
// enablementsJSON is the [json] representation of [Enablements]. // enablementsJSON is the [json] representation of [Enablements].
type enablementsJSON = struct { type enablementsJSON = struct {
Wayland bool `json:"wayland,omitempty"` Wayland bool `json:"wayland,omitempty"`
X11 bool `json:"x11,omitempty"` X11 bool `json:"x11,omitempty"`
DBus bool `json:"dbus,omitempty"` DBus bool `json:"dbus,omitempty"`
Pulse bool `json:"pulse,omitempty"` PipeWire bool `json:"pipewire,omitempty"`
Pulse bool `json:"pulse,omitempty"`
} }
// Unwrap returns the underlying [Enablement]. // Unwrap returns the underlying [Enablement].
@ -81,10 +86,11 @@ func (e *Enablements) MarshalJSON() ([]byte, error) {
return nil, syscall.EINVAL return nil, syscall.EINVAL
} }
return json.Marshal(&enablementsJSON{ return json.Marshal(&enablementsJSON{
Wayland: Enablement(*e)&EWayland != 0, Wayland: Enablement(*e)&EWayland != 0,
X11: Enablement(*e)&EX11 != 0, X11: Enablement(*e)&EX11 != 0,
DBus: Enablement(*e)&EDBus != 0, DBus: Enablement(*e)&EDBus != 0,
Pulse: Enablement(*e)&EPulse != 0, PipeWire: Enablement(*e)&EPipeWire != 0,
Pulse: Enablement(*e)&EPulse != 0,
}) })
} }
@ -108,6 +114,9 @@ func (e *Enablements) UnmarshalJSON(data []byte) error {
if v.DBus { if v.DBus {
ve |= EDBus ve |= EDBus
} }
if v.PipeWire {
ve |= EPipeWire
}
if v.Pulse { if v.Pulse {
ve |= EPulse ve |= EPulse
} }

View File

@ -32,6 +32,7 @@ func TestEnablementString(t *testing.T) {
{hst.EWayland | hst.EDBus | hst.EPulse, "wayland, dbus, pulseaudio"}, {hst.EWayland | hst.EDBus | hst.EPulse, "wayland, dbus, pulseaudio"},
{hst.EX11 | hst.EDBus | hst.EPulse, "x11, dbus, pulseaudio"}, {hst.EX11 | hst.EDBus | hst.EPulse, "x11, dbus, pulseaudio"},
{hst.EWayland | hst.EX11 | hst.EDBus | hst.EPulse, "wayland, x11, dbus, pulseaudio"}, {hst.EWayland | hst.EX11 | hst.EDBus | hst.EPulse, "wayland, x11, dbus, pulseaudio"},
{hst.EM - 1, "wayland, x11, dbus, pipewire, pulseaudio"},
{1 << 5, "e20"}, {1 << 5, "e20"},
{1 << 6, "e40"}, {1 << 6, "e40"},
@ -62,8 +63,9 @@ func TestEnablements(t *testing.T) {
{"wayland", hst.NewEnablements(hst.EWayland), `{"wayland":true}`, `{"value":{"wayland":true},"magic":3236757504}`}, {"wayland", hst.NewEnablements(hst.EWayland), `{"wayland":true}`, `{"value":{"wayland":true},"magic":3236757504}`},
{"x11", hst.NewEnablements(hst.EX11), `{"x11":true}`, `{"value":{"x11":true},"magic":3236757504}`}, {"x11", hst.NewEnablements(hst.EX11), `{"x11":true}`, `{"value":{"x11":true},"magic":3236757504}`},
{"dbus", hst.NewEnablements(hst.EDBus), `{"dbus":true}`, `{"value":{"dbus":true},"magic":3236757504}`}, {"dbus", hst.NewEnablements(hst.EDBus), `{"dbus":true}`, `{"value":{"dbus":true},"magic":3236757504}`},
{"pipewire", hst.NewEnablements(hst.EPipeWire), `{"pipewire":true}`, `{"value":{"pipewire":true},"magic":3236757504}`},
{"pulse", hst.NewEnablements(hst.EPulse), `{"pulse":true}`, `{"value":{"pulse":true},"magic":3236757504}`}, {"pulse", hst.NewEnablements(hst.EPulse), `{"pulse":true}`, `{"value":{"pulse":true},"magic":3236757504}`},
{"all", hst.NewEnablements(hst.EWayland | hst.EX11 | hst.EDBus | hst.EPulse), `{"wayland":true,"x11":true,"dbus":true,"pulse":true}`, `{"value":{"wayland":true,"x11":true,"dbus":true,"pulse":true},"magic":3236757504}`}, {"all", hst.NewEnablements(hst.EM - 1), `{"wayland":true,"x11":true,"dbus":true,"pipewire":true,"pulse":true}`, `{"value":{"wayland":true,"x11":true,"dbus":true,"pipewire":true,"pulse":true},"magic":3236757504}`},
} }
for _, tc := range testCases { for _, tc := range testCases {

View File

@ -70,7 +70,7 @@ func Template() *Config {
return &Config{ return &Config{
ID: "org.chromium.Chromium", ID: "org.chromium.Chromium",
Enablements: NewEnablements(EWayland | EDBus | EPulse), Enablements: NewEnablements(EWayland | EDBus | EPipeWire | EPulse),
SessionBus: &BusConfig{ SessionBus: &BusConfig{
See: nil, See: nil,

View File

@ -105,6 +105,7 @@ func TestTemplate(t *testing.T) {
"enablements": { "enablements": {
"wayland": true, "wayland": true,
"dbus": true, "dbus": true,
"pipewire": true,
"pulse": true "pulse": true
}, },
"session_bus": { "session_bus": {

View File

@ -172,6 +172,8 @@ type outcomeStateSys struct {
// Copied from [hst.Config]. Safe for read by spWaylandOp.toSystem only. // Copied from [hst.Config]. Safe for read by spWaylandOp.toSystem only.
directWayland bool directWayland bool
// Copied from [hst.Config]. Safe for read by spPulseOp.toSystem only.
directPulse bool
// Copied header from [hst.Config]. Safe for read by spFilesystemOp.toSystem only. // Copied header from [hst.Config]. Safe for read by spFilesystemOp.toSystem only.
extraPerms []hst.ExtraPermConfig extraPerms []hst.ExtraPermConfig
// Copied address from [hst.Config]. Safe for read by spDBusOp.toSystem only. // Copied address from [hst.Config]. Safe for read by spDBusOp.toSystem only.
@ -185,7 +187,8 @@ type outcomeStateSys struct {
func (s *outcomeState) newSys(config *hst.Config, sys *system.I) *outcomeStateSys { func (s *outcomeState) newSys(config *hst.Config, sys *system.I) *outcomeStateSys {
return &outcomeStateSys{ return &outcomeStateSys{
appId: config.ID, et: config.Enablements.Unwrap(), appId: config.ID, et: config.Enablements.Unwrap(),
directWayland: config.DirectWayland, extraPerms: config.ExtraPerms, directWayland: config.DirectWayland, directPulse: config.DirectPulse,
extraPerms: config.ExtraPerms,
sessionBus: config.SessionBus, systemBus: config.SystemBus, sessionBus: config.SessionBus, systemBus: config.SystemBus,
sys: sys, outcomeState: s, sys: sys, outcomeState: s,
} }

View File

@ -47,9 +47,9 @@ func TestEntryData(t *testing.T) {
{"inconsistent enablement", "\x00\xff\xca\xfe\x00\x00\xff\x00" + templateStateGob, NewTemplateState(), &hst.AppError{ {"inconsistent enablement", "\x00\xff\xca\xfe\x00\x00\xff\x00" + templateStateGob, NewTemplateState(), &hst.AppError{
Step: "validate state enablement", Err: os.ErrInvalid, Step: "validate state enablement", Err: os.ErrInvalid,
Msg: "state entry aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa has unexpected enablement byte 0xd, 0xff"}}, Msg: "state entry aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa has unexpected enablement byte 0x1d, 0xff"}},
{"template", "\x00\xff\xca\xfe\x00\x00\x0d\xf2" + templateStateGob, NewTemplateState(), nil}, {"template", "\x00\xff\xca\xfe\x00\x00\x1d\xe2" + templateStateGob, NewTemplateState(), nil},
} }
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {

View File

@ -34,7 +34,7 @@ func TestEntryHeader(t *testing.T) {
{"success high", [entryHeaderSize]byte{0x00, 0xff, 0xca, 0xfe, 0x00, 0x00, {"success high", [entryHeaderSize]byte{0x00, 0xff, 0xca, 0xfe, 0x00, 0x00,
0xff, 0x00}, 0xff, nil}, 0xff, 0x00}, 0xff, nil},
{"success", [entryHeaderSize]byte{0x00, 0xff, 0xca, 0xfe, 0x00, 0x00, {"success", [entryHeaderSize]byte{0x00, 0xff, 0xca, 0xfe, 0x00, 0x00,
0x09, 0xf6}, hst.EWayland | hst.EPulse, nil}, 0x09, 0xf6}, hst.EWayland | hst.EPipeWire, nil},
} }
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {