Ophestra 81430987e7
All checks were successful
Test / Create distribution (push) Successful in 6m57s
Test / Sandbox (push) Successful in 8m53s
Test / Hpkg (push) Successful in 10m40s
Test / Sandbox (race detector) (push) Successful in 10m50s
Test / Create distribution (pull_request) Successful in 10m12s
Test / Hakurei (race detector) (push) Successful in 11m27s
Test / Hakurei (race detector) (pull_request) Successful in 11m24s
Test / Sandbox (pull_request) Successful in 40s
Test / Sandbox (race detector) (pull_request) Successful in 40s
Test / Hpkg (pull_request) Successful in 41s
Test / Hakurei (push) Successful in 2m39s
Test / Hakurei (pull_request) Successful in 2m33s
Test / Flake checks (pull_request) Successful in 1m44s
Test / Flake checks (push) Successful in 1m46s
internal/pipewire: integrate pw_security_context
This is required for securely providing access to PipeWire.

This change has already been manually tested and confirmed to work correctly.

This unfortunately cannot be upstreamed in its current state as libpipewire-0.3 breaks static linking.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2025-11-19 06:37:30 +09:00

72 lines
1.9 KiB
Go

package pipewire
import (
"errors"
"os"
"syscall"
"hakurei.app/container/check"
)
// SecurityContext holds resources associated with a PipeWire security context.
type SecurityContext struct {
// Pipe with its write end passed to the PipeWire security context.
closeFds [2]int
}
// Close releases any resources held by [SecurityContext], and prevents further
// connections to its associated socket.
func (sc *SecurityContext) Close() error {
if sc == nil {
return os.ErrInvalid
}
return errors.Join(
syscall.Close(sc.closeFds[1]),
syscall.Close(sc.closeFds[0]),
)
}
// New creates a new security context on the PipeWire remote at remotePath
// or auto-detected, and associates it with a new socket bound to bindPath.
//
// New does not attach a finalizer to the resulting [SecurityContext] struct.
// The caller is responsible for calling [SecurityContext.Close].
//
// A non-nil error unwraps to concrete type [Error].
func New(remotePath, bindPath *check.Absolute) (*SecurityContext, error) {
// ensure bindPath is available
if f, err := os.Create(bindPath.String()); err != nil {
return nil, &Error{RCreate, bindPath.String(), err}
} else if err = f.Close(); err != nil {
return nil, &Error{RCreate, bindPath.String(), err}
} else if err = os.Remove(bindPath.String()); err != nil {
return nil, &Error{RCreate, bindPath.String(), err}
}
// write end passed to PipeWire security context close_fd
var closeFds [2]int
if err := syscall.Pipe2(closeFds[0:], syscall.O_CLOEXEC); err != nil {
return nil, err
}
// zero value causes auto-detect
var remotePathVal string
if remotePath != nil {
remotePathVal = remotePath.String()
}
// returned error is already wrapped
if err := securityContextBind(
bindPath.String(),
remotePathVal,
closeFds[1],
); err != nil {
return nil, errors.Join(err,
syscall.Close(closeFds[1]),
syscall.Close(closeFds[0]),
)
} else {
return &SecurityContext{closeFds}, nil
}
}