mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-10 16:43:12 +00:00
Fix rekey dual-initiation, parent selection, peer reconnect, and control socket
Rekey dual-initiation race (FMP + FSP): When both sides' rekey timers fire simultaneously on high-latency links (Tor ~700ms RTT), both msg1s cross in flight before dampening can suppress the second initiation. Each node acts as both initiator and responder, with set_pending_session() from the responder path destroying the initiator's in-progress state. Each side ends up with a pending_new_session from a different Noise handshake, causing AEAD verification failure after cutover and link death. Fix: deterministic tie-breaker in both FMP msg1 handler and FSP SessionSetup handler (smaller NodeAddr wins as initiator). Also guard against pending session overwrite from retransmitted msg1s. Parent selection SRTT gate: Peers without MMP RTT data are excluded from parent candidacy via has_srtt() filter, preventing freshly reconnected peers from appearing artificially attractive. First-RTT triggers immediate parent re-eval. The gate in evaluate_parent() skips unmeasured candidates when any peer has cost data, but falls back to default cost 1.0 during cold start when no peer has MMP data yet. Auto-reconnect on all peer removal paths: The excessive-decryption-failure and peer-restart epoch-mismatch removal paths were missing schedule_reconnect() calls, causing auto-connect peers to be permanently abandoned after those events. Control socket accessibility: Socket and parent directory chowned to root:fips with mode 0770/0750 so group members can use fipsctl/fipstop without root. Log level changes: Default RUST_LOG changed to debug in systemd service files. "Unknown session index" log reduced from debug to trace.
This commit is contained in:
@@ -54,6 +54,16 @@ impl ControlSocket {
|
||||
}
|
||||
|
||||
let listener = UnixListener::bind(&socket_path)?;
|
||||
|
||||
// Make the socket and its parent directory group-accessible so
|
||||
// 'fips' group members can use fipsctl/fipstop without root.
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
std::fs::set_permissions(&socket_path, std::fs::Permissions::from_mode(0o770))?;
|
||||
Self::chown_to_fips_group(&socket_path);
|
||||
if let Some(parent) = socket_path.parent() {
|
||||
Self::chown_to_fips_group(parent);
|
||||
}
|
||||
|
||||
info!(path = %socket_path.display(), "Control socket listening");
|
||||
|
||||
Ok(Self {
|
||||
@@ -85,6 +95,34 @@ impl ControlSocket {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set group ownership of a path to the 'fips' group (best-effort).
|
||||
fn chown_to_fips_group(path: &Path) {
|
||||
use std::ffi::CString;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
// Look up the 'fips' group
|
||||
let group_name = CString::new("fips").unwrap();
|
||||
let grp = unsafe { libc::getgrnam(group_name.as_ptr()) };
|
||||
if grp.is_null() {
|
||||
debug!("'fips' group not found, skipping chown for {}", path.display());
|
||||
return;
|
||||
}
|
||||
let gid = unsafe { (*grp).gr_gid };
|
||||
|
||||
let c_path = match CString::new(path.as_os_str().as_bytes()) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return,
|
||||
};
|
||||
let ret = unsafe { libc::chown(c_path.as_ptr(), u32::MAX, gid) };
|
||||
if ret != 0 {
|
||||
warn!(
|
||||
path = %path.display(),
|
||||
error = %std::io::Error::last_os_error(),
|
||||
"Failed to chown control socket to 'fips' group"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Run the accept loop, forwarding requests to the main event loop via mpsc.
|
||||
///
|
||||
/// Each accepted connection is handled in a spawned task:
|
||||
|
||||
Reference in New Issue
Block a user