aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-12-10 03:01:30 +0900
committerOphestra <cat@gensokyo.uk>2025-12-10 03:01:30 +0900
commitb72d502f1c5568cd8f93c9142247fa0d94caece5 (patch)
tree85a71fe040304d950e41e3f3021330fb141c6ad7
parentf8b3db3f6641f79cf1bf1bbb9aa28d6922afe422 (diff)
internal/outcome: populate instance metadata for PipeWire
These have similar semantics to equivalent Wayland security-context-v1 fields. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--internal/outcome/run_test.go10
-rw-r--r--internal/outcome/sppipewire.go7
-rw-r--r--internal/outcome/sppipewire_test.go4
-rw-r--r--internal/system/pipewire.go12
-rw-r--r--internal/system/pipewire_test.go70
5 files changed, 89 insertions, 14 deletions
diff --git a/internal/outcome/run_test.go b/internal/outcome/run_test.go
index f2aa1638..01d487a8 100644
--- a/internal/outcome/run_test.go
+++ b/internal/outcome/run_test.go
@@ -68,7 +68,11 @@ func TestOutcomeRun(t *testing.T) {
).
// spPipeWireOp
- PipeWire(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/pipewire")).
+ PipeWire(
+ m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/pipewire"),
+ "org.chromium.Chromium",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ ).
// spDBusOp
MustProxyDBus(
@@ -335,7 +339,7 @@ func TestOutcomeRun(t *testing.T) {
Ensure(m("/tmp/hakurei.0/tmpdir/9"), 01700).UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/9"), acl.Read, acl.Write, acl.Execute).
Ephemeral(system.Process, m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c"), 0711).
Wayland(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/wayland"), m("/run/user/1971/wayland-0"), "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c").
- PipeWire(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/pipewire")).
+ PipeWire(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/pipewire"), "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c").
MustProxyDBus(&hst.BusConfig{
Talk: []string{
"org.freedesktop.Notifications",
@@ -486,7 +490,7 @@ func TestOutcomeRun(t *testing.T) {
Ensure(m("/run/user/1971/hakurei"), 0700).UpdatePermType(system.User, m("/run/user/1971/hakurei"), acl.Execute).
UpdatePermType(hst.EWayland, m("/run/user/1971/wayland-0"), acl.Read, acl.Write, acl.Execute).
Ephemeral(system.Process, m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1"), 0711).
- PipeWire(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/pipewire")).
+ PipeWire(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/pipewire"), "org.chromium.Chromium", "8e2c76b066dabe574cf073bdb46eb5c1").
MustProxyDBus(&hst.BusConfig{
Talk: []string{
"org.freedesktop.FileManager1", "org.freedesktop.Notifications",
diff --git a/internal/outcome/sppipewire.go b/internal/outcome/sppipewire.go
index b8c855f6..b9359f7e 100644
--- a/internal/outcome/sppipewire.go
+++ b/internal/outcome/sppipewire.go
@@ -18,7 +18,12 @@ func (s spPipeWireOp) toSystem(state *outcomeStateSys) error {
return errNotEnabled
}
- state.sys.PipeWire(state.instance().Append("pipewire"))
+ appId := state.appId
+ if appId == "" {
+ // use instance ID in case app id is not set
+ appId = "app.hakurei." + state.id.String()
+ }
+ state.sys.PipeWire(state.instance().Append("pipewire"), appId, state.id.String())
return nil
}
diff --git a/internal/outcome/sppipewire_test.go b/internal/outcome/sppipewire_test.go
index d53f6d6d..35ad8e50 100644
--- a/internal/outcome/sppipewire_test.go
+++ b/internal/outcome/sppipewire_test.go
@@ -30,7 +30,9 @@ func TestSpPipeWireOp(t *testing.T) {
Ephemeral(system.Process, m(wantInstancePrefix), 0711).
// toSystem
PipeWire(
- m(wantInstancePrefix + "/pipewire"),
+ m(wantInstancePrefix+"/pipewire"),
+ "org.chromium.Chromium",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
), sysUsesInstance(nil), nil, insertsOps(afterSpRuntimeOp(nil)), []stub.Call{
// this op configures the container state and does not make calls during toContainer
}, &container.Params{
diff --git a/internal/system/pipewire.go b/internal/system/pipewire.go
index 45b1e8ba..d04cae41 100644
--- a/internal/system/pipewire.go
+++ b/internal/system/pipewire.go
@@ -14,8 +14,8 @@ import (
// PipeWire maintains a pipewire socket with SecurityContext attached via [pipewire].
// The socket stops accepting connections once the pipe referred to by sync is closed.
// The socket is pathname only and is destroyed on revert.
-func (sys *I) PipeWire(dst *check.Absolute) *I {
- sys.ops = append(sys.ops, &pipewireOp{nil, dst})
+func (sys *I) PipeWire(dst *check.Absolute, appID, instanceID string) *I {
+ sys.ops = append(sys.ops, &pipewireOp{nil, dst, appID, instanceID})
return sys
}
@@ -23,6 +23,8 @@ func (sys *I) PipeWire(dst *check.Absolute) *I {
type pipewireOp struct {
scc io.Closer
dst *check.Absolute
+
+ appID, instanceID string
}
func (p *pipewireOp) Type() hst.Enablement { return Process }
@@ -56,6 +58,8 @@ func (p *pipewireOp) apply(sys *I) (err error) {
if p.scc, err = securityContext.BindAndCreate(p.dst.String(), pipewire.SPADict{
{Key: pipewire.PW_KEY_SEC_ENGINE, Value: "app.hakurei"},
+ {Key: pipewire.PW_KEY_SEC_APP_ID, Value: p.appID},
+ {Key: pipewire.PW_KEY_SEC_INSTANCE_ID, Value: p.instanceID},
{Key: pipewire.PW_KEY_ACCESS, Value: "restricted"},
}); err != nil {
return newOpError("pipewire", err, false)
@@ -92,7 +96,9 @@ func (p *pipewireOp) revert(sys *I, _ *Criteria) error {
func (p *pipewireOp) Is(o Op) bool {
target, ok := o.(*pipewireOp)
return ok && p != nil && target != nil &&
- p.dst.Is(target.dst)
+ p.dst.Is(target.dst) &&
+ p.appID == target.appID &&
+ p.instanceID == target.instanceID
}
func (p *pipewireOp) Path() string { return p.dst.String() }
diff --git a/internal/system/pipewire_test.go b/internal/system/pipewire_test.go
index 127e3f25..9c4950c6 100644
--- a/internal/system/pipewire_test.go
+++ b/internal/system/pipewire_test.go
@@ -18,6 +18,8 @@ func TestPipeWireOp(t *testing.T) {
checkOpBehaviour(t, checkNoParallel, []opBehaviourTestCase{
{"success", 0xbeef, 0xff, &pipewireOp{nil,
m(path.Join(t.TempDir(), "pipewire")),
+ "org.chromium.Chromium",
+ "ebf083d1b175911782d413369b64ce7c",
}, []stub.Call{
call("pipewireConnect", stub.ExpectArgs{}, func() *pipewire.Context {
if ctx, err := pipewire.New(&stubPipeWireConn{sendmsg: []string{
@@ -154,11 +156,11 @@ func TestPipeWireOp(t *testing.T) {
string([]byte{
// header: SecurityContext::Create
3, 0, 0, 0,
- 0xa8, 0, 0, 1,
+ 0x40, 1, 0, 1,
5, 0, 0, 0,
2, 0, 0, 0,
// Struct
- 0xa0, 0, 0, 0,
+ 0x38, 1, 0, 0,
0xe, 0, 0, 0,
// Fd: listen_fd = 1
8, 0, 0, 0,
@@ -171,12 +173,12 @@ func TestPipeWireOp(t *testing.T) {
0, 0, 0, 0,
0, 0, 0, 0,
// Struct: spa_dict
- 0x78, 0, 0, 0,
+ 0x10, 1, 0, 0,
0xe, 0, 0, 0,
- // Int: n_items = 2
+ // Int: n_items = 4
+ 4, 0, 0, 0,
4, 0, 0, 0,
4, 0, 0, 0,
- 2, 0, 0, 0,
0, 0, 0, 0,
// String: key = "pipewire.sec.engine"
0x14, 0, 0, 0,
@@ -194,6 +196,48 @@ func TestPipeWireOp(t *testing.T) {
0x68, 0x61, 0x6b, 0x75,
0x72, 0x65, 0x69, 0,
0, 0, 0, 0,
+ // String: key = "pipewire.sec.app-id"
+ 0x14, 0, 0, 0,
+ 8, 0, 0, 0,
+ 0x70, 0x69, 0x70, 0x65,
+ 0x77, 0x69, 0x72, 0x65,
+ 0x2e, 0x73, 0x65, 0x63,
+ 0x2e, 0x61, 0x70, 0x70,
+ 0x2d, 0x69, 0x64, 0,
+ 0, 0, 0, 0,
+ // String: value = "org.chromium.Chromium"
+ 0x16, 0, 0, 0,
+ 8, 0, 0, 0,
+ 0x6f, 0x72, 0x67, 0x2e,
+ 0x63, 0x68, 0x72, 0x6f,
+ 0x6d, 0x69, 0x75, 0x6d,
+ 0x2e, 0x43, 0x68, 0x72,
+ 0x6f, 0x6d, 0x69, 0x75,
+ // String: key = "pipewire.sec.instance-id"
+ 0x6d, 0, 0, 0,
+ 0x19, 0, 0, 0,
+ 8, 0, 0, 0,
+ 0x70, 0x69, 0x70, 0x65,
+ 0x77, 0x69, 0x72, 0x65,
+ 0x2e, 0x73, 0x65, 0x63,
+ 0x2e, 0x69, 0x6e, 0x73,
+ 0x74, 0x61, 0x6e, 0x63,
+ 0x65, 0x2d, 0x69, 0x64,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ // String: value = "ebf083d1b175911782d413369b64ce7c"
+ 0x21, 0, 0, 0,
+ 8, 0, 0, 0,
+ 0x65, 0x62, 0x66, 0x30,
+ 0x38, 0x33, 0x64, 0x31,
+ 0x62, 0x31, 0x37, 0x35,
+ 0x39, 0x31, 0x31, 0x37,
+ 0x38, 0x32, 0x64, 0x34,
+ 0x31, 0x33, 0x33, 0x36,
+ 0x39, 0x62, 0x36, 0x34,
+ 0x63, 0x65, 0x37, 0x63,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
// String: key = "pipewire.access"
0x10, 0, 0, 0,
8, 0, 0, 0,
@@ -386,29 +430,43 @@ func TestPipeWireOp(t *testing.T) {
checkOpsBuilder(t, "PipeWire", []opsBuilderTestCase{
{"sample", 0xcafe, func(_ *testing.T, sys *I) {
- sys.PipeWire(m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"))
+ sys.PipeWire(m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
+ "org.chromium.Chromium",
+ "ebf083d1b175911782d413369b64ce7c")
}, []Op{&pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
+ "org.chromium.Chromium",
+ "ebf083d1b175911782d413369b64ce7c",
}}, stub.Expect{}},
})
checkOpIs(t, []opIsTestCase{
{"dst differs", &pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7d/pipewire"),
+ "org.chromium.Chromium",
+ "ebf083d1b175911782d413369b64ce7c",
}, &pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
+ "org.chromium.Chromium",
+ "ebf083d1b175911782d413369b64ce7c",
}, false},
{"equals", &pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
+ "org.chromium.Chromium",
+ "ebf083d1b175911782d413369b64ce7c",
}, &pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
+ "org.chromium.Chromium",
+ "ebf083d1b175911782d413369b64ce7c",
}, true},
})
checkOpMeta(t, []opMetaTestCase{
{"sample", &pipewireOp{nil,
m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"),
+ "org.chromium.Chromium",
+ "ebf083d1b175911782d413369b64ce7c",
}, Process, "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire",
`pipewire socket at "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/pipewire"`},
})