aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/wayland/conn.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-11-19 05:41:29 +0900
committerOphestra <cat@gensokyo.uk>2025-11-19 06:37:04 +0900
commitaab92ce3c1c6649e1a22b00ec999a271e71ef291 (patch)
tree3ccfa205103382e9a4cbc225e71ba9f57ac64f94 /internal/wayland/conn.go
parenta495e09a8f11041fb23a9587c0dc9f52513a2937 (diff)
internal/wayland: clean up pathname socket
This is cleaner than cleaning up in internal/system as it covers the failure paths. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/wayland/conn.go')
-rw-r--r--internal/wayland/conn.go29
1 files changed, 25 insertions, 4 deletions
diff --git a/internal/wayland/conn.go b/internal/wayland/conn.go
index fa7ced8c..40a909e7 100644
--- a/internal/wayland/conn.go
+++ b/internal/wayland/conn.go
@@ -12,18 +12,32 @@ import (
type SecurityContext struct {
// Pipe with its write end passed to security-context-v1.
closeFds [2]int
+ // Absolute pathname the socket was bound to.
+ bindPath *check.Absolute
}
// Close releases any resources held by [SecurityContext], and prevents further
// connections to its associated socket.
+//
+// A non-nil error has the concrete type [Error].
func (sc *SecurityContext) Close() error {
- if sc == nil {
+ if sc == nil || sc.bindPath == nil {
return os.ErrInvalid
}
- return errors.Join(
+
+ e := Error{RCleanup, sc.bindPath.String(), "", errors.Join(
syscall.Close(sc.closeFds[1]),
syscall.Close(sc.closeFds[0]),
- )
+ // there is still technically a TOCTOU here but this is internal
+ // and has access to the privileged wayland socket, so it only
+ // receives trusted input (e.g. from cmd/hakurei) anyway
+ os.Remove(sc.bindPath.String()),
+ )}
+ if e.Errno != nil {
+ return &e
+ }
+
+ return nil
}
// New creates a new security context on the Wayland display at displayPath
@@ -51,12 +65,19 @@ func New(displayPath, bindPath *check.Absolute, appID, instanceID string) (*Secu
} else {
closeFds, bindErr := securityContextBindPipe(fd, bindPath, appID, instanceID)
if bindErr != nil {
+ // securityContextBindPipe does not try to remove the socket during cleanup
+ closeErr := os.Remove(bindPath.String())
+ if closeErr != nil && errors.Is(closeErr, os.ErrNotExist) {
+ closeErr = nil
+ }
+
err = errors.Join(bindErr, // already wrapped
+ closeErr,
// do not leak the socket
syscall.Close(fd),
)
}
- return &SecurityContext{closeFds}, err
+ return &SecurityContext{closeFds, bindPath}, err
}
}