config: unify default control-socket path resolution

Daemon and client tools previously evaluated the same three locations
(`/run/fips`, `XDG_RUNTIME_DIR`, `/tmp`) in different orders, allowing
fipsctl/fipstop to connect to a socket the daemon never bound when
neither side set `node.control.socket_path` explicitly.

Collapse the three call sites (`default_control_path`,
`default_gateway_path`, `ControlConfig::default_socket_path`) into a
shared `resolve_default_socket` helper. Canonical order is
`/run/fips` -> `$XDG_RUNTIME_DIR/fips/` -> `/tmp/fips-<name>`. Two
hardening fixes folded in: writability is probed via tempfile create
rather than mode bits (ACL- and group-aware), and `XDG_RUNTIME_DIR`
is validated as an existing directory before being used (avoids
stale post-logout values).

The deployed fleet is unaffected -- packaged configs set
`node.control.socket_path` explicitly. The fix surfaces for dev
runs and the binary-install getting-started path.
This commit is contained in:
Johnathan Corgan
2026-05-08 13:37:16 +00:00
parent 18019bb1b5
commit db5b6b10bd
4 changed files with 210 additions and 30 deletions
+6 -11
View File
@@ -780,20 +780,15 @@ impl ControlConfig {
/// Default control socket path.
///
/// On Unix, returns a Unix domain socket path (XDG_RUNTIME_DIR, /run/fips,
/// or /tmp fallback). On Windows, returns a TCP port number as a string
/// since Windows does not support Unix domain sockets; the control socket
/// listens on localhost at this port.
/// On Unix, delegates to [`super::resolve_default_socket`] for the
/// canonical `/run/fips` → `XDG_RUNTIME_DIR` → `/tmp` order shared with
/// the client-side `default_control_path`. On Windows, returns a TCP
/// port number as a string since Windows does not support Unix domain
/// sockets; the control socket listens on localhost at this port.
fn default_socket_path() -> String {
#[cfg(unix)]
{
if let Ok(runtime_dir) = std::env::var("XDG_RUNTIME_DIR") {
format!("{runtime_dir}/fips/control.sock")
} else if std::fs::create_dir_all("/run/fips").is_ok() {
"/run/fips/control.sock".to_string()
} else {
"/tmp/fips-control.sock".to_string()
}
super::resolve_default_socket("control.sock")
}
#[cfg(windows)]
{