Skip to content

Commit 6ebc7fa

Browse files
committed
Wait for admin goroutine to create control socket before changing user
Otherwise the main goroutine races dropping privileges races against those carrying out privileges tasks at startup. Reproducible at least on OpenBSD/amd64 7.6-current, where it (expectedly) fails to create a UNIX socket in `0755 root:wheel /var/run/` *after* calling setuid(2) to `nobody`: ``` # yggdrasil -autoconf -user nobody 2024/11/03 21:15:27 Build name: yggdrasil-go 2024/11/03 21:15:27 Build version: 0.5.9 ... 2024/11/03 21:15:27 Admin socket failed to listen: listen unix /var/run/yggdrasil.sock: bind: permission denied ``` Rerun, now the order is flipped: ``` # yggdrasil -autoconf -user nobody 2024/11/03 21:15:34 Build name: yggdrasil-go 2024/11/03 21:15:34 Build version: 0.5.9 [...] 2024/11/03 21:15:34 UNIX admin socket listening on /var/run/yggdrasil.sock [...] ``` The `AdminSocket`s `done` channel is insufficient to sync here, waiting for `n.admin.IsStarted()` does not guarantee socket creation, so export a simple boolean instead. This is a minimal fix to prevent startup failure; TUN interface and raw socket creation (to manage routes) might suffer the same problem, but I have not seem them fail yet. Fixes yggdrasil-network#927.
1 parent eef6139 commit 6ebc7fa

File tree

2 files changed

+10
-0
lines changed

2 files changed

+10
-0
lines changed

cmd/yggdrasil/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,14 @@ func main() {
281281
<-done
282282
})
283283

284+
// Wait for other goroutines to finish potentially privileged tasks before dropping privileges.
285+
for {
286+
// control socket: UNIX requires filesystem permissions, TCP may use a low privileged port.
287+
if n.admin.Created {
288+
break
289+
}
290+
}
291+
284292
// Change user if requested
285293
if *chuserto != "" {
286294
err = chuser(*chuserto)

src/admin/admin.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type AdminSocket struct {
2626
config struct {
2727
listenaddr ListenAddress
2828
}
29+
Created bool
2930
}
3031

3132
type AdminSocketRequest struct {
@@ -274,6 +275,7 @@ func (a *AdminSocket) listen() {
274275
a.log.Errorf("Admin socket failed to listen: %v", err)
275276
os.Exit(1)
276277
}
278+
a.Created = true
277279
a.log.Infof("%s admin socket listening on %s",
278280
strings.ToUpper(a.listener.Addr().Network()),
279281
a.listener.Addr().String())

0 commit comments

Comments
 (0)