diff --git a/docs/gateway.md b/docs/gateway.md index f486c51d..38d86296 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -107,9 +107,12 @@ now set unconditionally for every agent. The mechanism: Do **not** reintroduce a chown here: tmpfiles re-applies this entry on every boot *and* every agent spawn/destroy, so any ownership set afterwards is reverted the next time any agent changes. The mode is - also load-bearing — a directory without the sticky bit lets any user - unlink files in it, so a world-writable socket dir would let anything - that can reach the path replace an agent's socket with its own. + also load-bearing — write permission on a *directory* is what confers + the right to unlink its entries, whoever owns them, and the sticky bit + is the only thing that would restrain that (it is not set here). So a + world-writable socket dir would let anything able to reach the path + replace an agent's socket with its own; `o=--x` removes that + permission outright rather than qualifying it. 3. **Marker gate**. After successful `bind_unix`, the harness drops `/hyperhive-socket-bound` next to the socket. c0re's `agent_sockets::write` filters its JSON map by marker presence — diff --git a/hive-priv/src/main.rs b/hive-priv/src/main.rs index 27312cb4..fb9b8ee7 100644 --- a/hive-priv/src/main.rs +++ b/hive-priv/src/main.rs @@ -2430,11 +2430,15 @@ async fn sync_agent_tmpfiles(agents: &[AgentTmpfilesEntry]) -> Result<(String, S // (dials web.sock, and has all of /run/hive-agent bind-mounted in). // Both sockets are 0666, so traversal is all they need. // - // 0751 rather than the historical 0777 is a fix, not a tidy-up: a - // directory without the sticky bit lets *any* user unlink files in it, - // so world-writable here means anything that can reach the path could - // delete an agent's socket, bind its own, and receive that agent's - // todos. Declaring the owner here also ends the tug-of-war with the + // 0751 rather than the historical 0777 is a fix, not a tidy-up: + // write permission on a *directory* is what confers the right to + // unlink its entries, whoever owns them — the sticky bit is the only + // thing that would restrain that, and it was never set here. So the + // old world-writable mode let anything able to reach the path delete + // an agent's socket, bind its own, and receive that agent's todos. + // Dropping `o=w` removes that permission outright rather than + // qualifying it. Declaring the owner here also ends the tug-of-war + // with the // old ChownSocketDir: `d` re-applies on every sync, so a chown made // afterwards was reset by the next agent's spawn. if let (Some(uid), Some(gid)) = (entry.uid, entry.gid) {