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));