diff --git a/cmd/hakurei/print_test.go b/cmd/hakurei/print_test.go index 1d6f511..d0c12d1 100644 --- a/cmd/hakurei/print_test.go +++ b/cmd/hakurei/print_test.go @@ -32,7 +32,7 @@ var ( PID: 0xbeef, ShimPID: 0xcafe, Config: &hst.Config{ - Enablements: hst.NewEnablements(hst.EWayland | hst.EPulse), + Enablements: hst.NewEnablements(hst.EWayland | hst.EPipeWire), Identity: 1, Container: &hst.ContainerConfig{ 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}, {"config", nil, hst.Template(), false, false, `App Identity: 9 (org.chromium.Chromium) - Enablements: wayland, dbus, pulseaudio + Enablements: wayland, dbus, pipewire, pulseaudio Groups: video, dialout, plugdev Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir Home: /data/data/org.chromium.Chromium @@ -159,7 +159,7 @@ Session bus App Identity: 9 (org.chromium.Chromium) - Enablements: wayland, dbus, pulseaudio + Enablements: wayland, dbus, pipewire, pulseaudio Groups: video, dialout, plugdev Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, runtime, tmpdir Home: /data/data/org.chromium.Chromium @@ -215,6 +215,7 @@ App "enablements": { "wayland": true, "dbus": true, + "pipewire": true, "pulse": true }, "session_bus": { @@ -366,6 +367,7 @@ App "enablements": { "wayland": true, "dbus": true, + "pipewire": true, "pulse": true }, "session_bus": { @@ -564,6 +566,7 @@ func TestPrintPs(t *testing.T) { "enablements": { "wayland": true, "dbus": true, + "pipewire": true, "pulse": true }, "session_bus": { @@ -715,7 +718,7 @@ func TestPrintPs(t *testing.T) { "shim_pid": 51966, "enablements": { "wayland": true, - "pulse": true + "pipewire": true }, "identity": 1, "groups": null, diff --git a/hst/config.go b/hst/config.go index d707855..c6cd790 100644 --- a/hst/config.go +++ b/hst/config.go @@ -23,9 +23,20 @@ type Config struct { // System D-Bus proxy configuration. // If set to nil, system bus proxy is disabled. 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. + // + // 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"` + // 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. ExtraPerms []ExtraPermConfig `json:"extra_perms,omitempty"` diff --git a/hst/enablement.go b/hst/enablement.go index 7a1056d..9024078 100644 --- a/hst/enablement.go +++ b/hst/enablement.go @@ -17,6 +17,8 @@ const ( EX11 // EDBus enables the per-container xdg-dbus-proxy daemon. EDBus + // EPipeWire exposes a pipewire pathname socket via SecurityContext. + EPipeWire // EPulse copies the PulseAudio cookie to [hst.PrivateTmp] and exposes the PulseAudio socket. EPulse @@ -35,6 +37,8 @@ func (e Enablement) String() string { return "x11" case EDBus: return "dbus" + case EPipeWire: + return "pipewire" case EPulse: return "pulseaudio" default: @@ -62,10 +66,11 @@ type Enablements Enablement // enablementsJSON is the [json] representation of [Enablements]. type enablementsJSON = struct { - Wayland bool `json:"wayland,omitempty"` - X11 bool `json:"x11,omitempty"` - DBus bool `json:"dbus,omitempty"` - Pulse bool `json:"pulse,omitempty"` + Wayland bool `json:"wayland,omitempty"` + X11 bool `json:"x11,omitempty"` + DBus bool `json:"dbus,omitempty"` + PipeWire bool `json:"pipewire,omitempty"` + Pulse bool `json:"pulse,omitempty"` } // Unwrap returns the underlying [Enablement]. @@ -81,10 +86,11 @@ func (e *Enablements) MarshalJSON() ([]byte, error) { return nil, syscall.EINVAL } return json.Marshal(&enablementsJSON{ - Wayland: Enablement(*e)&EWayland != 0, - X11: Enablement(*e)&EX11 != 0, - DBus: Enablement(*e)&EDBus != 0, - Pulse: Enablement(*e)&EPulse != 0, + Wayland: Enablement(*e)&EWayland != 0, + X11: Enablement(*e)&EX11 != 0, + DBus: Enablement(*e)&EDBus != 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 { ve |= EDBus } + if v.PipeWire { + ve |= EPipeWire + } if v.Pulse { ve |= EPulse } diff --git a/hst/enablement_test.go b/hst/enablement_test.go index 75d8d94..5ba9b71 100644 --- a/hst/enablement_test.go +++ b/hst/enablement_test.go @@ -32,6 +32,7 @@ func TestEnablementString(t *testing.T) { {hst.EWayland | hst.EDBus | hst.EPulse, "wayland, dbus, pulseaudio"}, {hst.EX11 | hst.EDBus | hst.EPulse, "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 << 6, "e40"}, @@ -62,8 +63,9 @@ func TestEnablements(t *testing.T) { {"wayland", hst.NewEnablements(hst.EWayland), `{"wayland":true}`, `{"value":{"wayland":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}`}, + {"pipewire", hst.NewEnablements(hst.EPipeWire), `{"pipewire":true}`, `{"value":{"pipewire":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 { diff --git a/hst/hst.go b/hst/hst.go index f48b9f8..a7f9092 100644 --- a/hst/hst.go +++ b/hst/hst.go @@ -70,7 +70,7 @@ func Template() *Config { return &Config{ ID: "org.chromium.Chromium", - Enablements: NewEnablements(EWayland | EDBus | EPulse), + Enablements: NewEnablements(EWayland | EDBus | EPipeWire | EPulse), SessionBus: &BusConfig{ See: nil, diff --git a/hst/hst_test.go b/hst/hst_test.go index b487dd5..01d229f 100644 --- a/hst/hst_test.go +++ b/hst/hst_test.go @@ -105,6 +105,7 @@ func TestTemplate(t *testing.T) { "enablements": { "wayland": true, "dbus": true, + "pipewire": true, "pulse": true }, "session_bus": { diff --git a/internal/outcome/outcome.go b/internal/outcome/outcome.go index e256355..3252db9 100644 --- a/internal/outcome/outcome.go +++ b/internal/outcome/outcome.go @@ -172,6 +172,8 @@ type outcomeStateSys struct { // Copied from [hst.Config]. Safe for read by spWaylandOp.toSystem only. 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. extraPerms []hst.ExtraPermConfig // 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 { return &outcomeStateSys{ 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, sys: sys, outcomeState: s, } diff --git a/internal/store/data_test.go b/internal/store/data_test.go index fe0e212..a2eb92c 100644 --- a/internal/store/data_test.go +++ b/internal/store/data_test.go @@ -47,9 +47,9 @@ func TestEntryData(t *testing.T) { {"inconsistent enablement", "\x00\xff\xca\xfe\x00\x00\xff\x00" + templateStateGob, NewTemplateState(), &hst.AppError{ 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 { t.Run(tc.name, func(t *testing.T) { diff --git a/internal/store/header_test.go b/internal/store/header_test.go index 51a6939..9da547f 100644 --- a/internal/store/header_test.go +++ b/internal/store/header_test.go @@ -34,7 +34,7 @@ func TestEntryHeader(t *testing.T) { {"success high", [entryHeaderSize]byte{0x00, 0xff, 0xca, 0xfe, 0x00, 0x00, 0xff, 0x00}, 0xff, nil}, {"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 { t.Run(tc.name, func(t *testing.T) {