From f10f8a6bc60d181a7cdff1d1f48fc9d0f0b95ccc Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 5 Aug 2026 11:32:53 +0200 Subject: [PATCH] fix(swarm-controller): the socket needs 0666, the directory is the guard bind leaves a unix socket 0755 and connecting needs write, so the gateway's nginx -- a different user -- would be locked out. 0666 is what hive-c0re already does for the per-agent sockets, and it rests on the same argument: the containing directory is the access control, not the socket mode. This directory holds one socket and is bind-mounted into exactly one container. That is also the sharper reason the socket does not live beside the host admin socket. With a 0666 socket, a directory that carries more than it should is not untidiness, it is the vulnerability. --- swarm-controller/src/main.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/swarm-controller/src/main.rs b/swarm-controller/src/main.rs index d6230d84..581116c9 100644 --- a/swarm-controller/src/main.rs +++ b/swarm-controller/src/main.rs @@ -12,6 +12,7 @@ //! Distinct from `hive-c0re`, which is per-hive: c0re owns the agents on //! one host, this owns what is true across hives. +use std::os::unix::fs::PermissionsExt as _; use std::path::PathBuf; use anyhow::{Context, Result}; @@ -67,6 +68,18 @@ async fn main() -> Result<()> { let listener = tokio::net::UnixListener::bind(&path) .with_context(|| format!("binding {}", path.display()))?; + + // `bind` leaves the socket 0755, and connecting needs write — the + // gateway's nginx is a different user, so it would be locked out. + // 0666 matches how hive-c0re publishes the per-agent sockets + // (`socket_server::start`), and rests on the same argument: **the + // containing directory is the access control, not the socket mode.** + // This directory holds one socket and is bind-mounted into exactly + // one container. That is also why it must not be shared with + // hive-c0re's `/run/hyperhive` — with a 0666 socket, a directory + // that carries more than it should is the whole vulnerability. + std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o666)) + .with_context(|| format!("chmod {}", path.display()))?; tracing::info!(socket = %path.display(), "swarm-controller listening"); let app = Router::new().route("/health", get(health));