From 150d058dec6d582c4dba0e99b25e6fa0d4695e7b Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Wed, 9 Sep 2026 12:45:56 +0200 Subject: [PATCH] Start background work only once the daemon sockets are bound --- client/cmd/service_allow_group_unix.go | 8 +++++--- client/cmd/service_controller.go | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/client/cmd/service_allow_group_unix.go b/client/cmd/service_allow_group_unix.go index 24c821755..6b2633531 100644 --- a/client/cmd/service_allow_group_unix.go +++ b/client/cmd/service_allow_group_unix.go @@ -36,9 +36,11 @@ const ( // account planted. A restricted socket binds owner-only and applySocketAccess // hands it to the group, under the checks that step carries. // -// The umask is process-wide, so it is restored immediately and the window is -// the bind alone. Nothing else creates files at this point in startup: the -// server and its goroutines do not exist yet. +// The umask is process-wide, so a file another goroutine creates during the +// bind would inherit it. That is why Start defers every asynchronous step until +// the listeners exist: at this point the daemon is still single-threaded, and +// the window is the bind call alone. A background task introduced above the +// listeners in Start would reopen this, which is what the note there is for. func listenUnixPrivate(address string, allowed []string) (net.Listener, error) { mode := openSocketMode if len(allowed) > 0 { diff --git a/client/cmd/service_controller.go b/client/cmd/service_controller.go index 102fa6cec..7995fa056 100644 --- a/client/cmd/service_controller.go +++ b/client/cmd/service_controller.go @@ -65,9 +65,6 @@ func (p *program) Start(svc service.Service) error { return err } - // Collect static system and platform information - system.UpdateStaticInfoAsync() - // A daemon installed before named-pipe support has the loopback TCP address // persisted. Move it to the named pipe so an upgraded daemon can identify // its callers instead of silently serving an unauthenticated socket. @@ -100,6 +97,12 @@ func (p *program) Start(svc service.Service) error { return err } + // Started only once the sockets exist. Binding them adjusts the process + // umask for the length of the bind, and a goroutine creating a file in that + // window would inherit it, so nothing asynchronous may be in flight before + // this point. Keep any future background work below the listeners too. + system.UpdateStaticInfoAsync() + go func() { // Fatal here rather than inside serve, so serve's deferred listener // closes run before the process exits.