From 7c6fc1128b89ebfc22adc52bac1fdb9205e69150 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sun, 7 Dec 2025 17:29:22 +0900 Subject: [PATCH] internal/pipewire: set finalizer on scc This prevents leaking the socket and pipe fds. Signed-off-by: Ophestra --- internal/pipewire/securitycontext.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/internal/pipewire/securitycontext.go b/internal/pipewire/securitycontext.go index 107fe99..c50665b 100644 --- a/internal/pipewire/securitycontext.go +++ b/internal/pipewire/securitycontext.go @@ -4,6 +4,7 @@ import ( "errors" "io" "os" + "runtime" "syscall" ) @@ -125,8 +126,8 @@ type securityContextCloser struct { } // Close closes both ends of the pipe. -func (scc *securityContextCloser) Close() error { - return errors.Join( +func (scc *securityContextCloser) Close() (err error) { + err = errors.Join( syscall.Close(scc.closeFds[1]), syscall.Close(scc.closeFds[0]), // there is still technically a TOCTOU here but this is internal @@ -134,6 +135,10 @@ func (scc *securityContextCloser) Close() error { // receives trusted input (e.g. from cmd/hakurei) anyway os.Remove(scc.pathname), ) + + // no need for a finalizer anymore + runtime.SetFinalizer(scc, nil) + return } // BindAndCreate binds a new socket to the specified pathname and pass it to Create. @@ -162,6 +167,7 @@ func (securityContext *SecurityContext) BindAndCreate(pathname string, props SPA if err := syscall.Bind(listenFd, &syscall.SockaddrUnix{Name: pathname}); err != nil { return nil, os.NewSyscallError("bind", err) } else if err = syscall.Listen(listenFd, 0); err != nil { + _ = os.Remove(pathname) return nil, os.NewSyscallError("listen", err) } @@ -169,6 +175,8 @@ func (securityContext *SecurityContext) BindAndCreate(pathname string, props SPA _ = os.Remove(pathname) return nil, err } + runtime.SetFinalizer(&scc, (*securityContextCloser).Close) + if err := securityContext.Create(listenFd, scc.closeFds[1], props); err != nil { _ = scc.Close() return nil, err