From 9dd427d49fb903c7a664ad412267d8cb495cd939 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 6 Sep 2026 09:24:58 +0800 Subject: [PATCH] test(linux): pin the exe-check wiring, not just the pure decision The matrix test covers `should_defer_exe_check_to_uid_gate` in isolation, so rerouting the authorization path (e.g. degrading without consulting the server's privilege) would still pass CI. Add an end-to-end test over `ensure_peer_executable_matches_current_by_pid` using PID 1 as a real peer whose executable differs from the test binary: an unprivileged server cannot read its /proc//exe and must defer to the uid gate, while a server that can read it must still reject the mismatch. Both outcomes are asserted, so the test is meaningful whether CI runs as root or not. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Lq6xFoeEmjcuKwRx1GfdQ2 --- src/ipc/auth.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/ipc/auth.rs b/src/ipc/auth.rs index 845e0fbda..2f3a7b278 100644 --- a/src/ipc/auth.rs +++ b/src/ipc/auth.rs @@ -1135,4 +1135,46 @@ mod tests { false )); } + + // The matrix test above pins the pure decision; this one pins the WIRING, so rerouting the + // authorization path (e.g. degrading without consulting the server's privilege) cannot pass CI. + // PID 1 is a real peer whose executable differs from the test binary: an unprivileged server + // cannot read its /proc//exe and must defer to the uid gate, while a server that can read + // it must still reject the mismatch. + #[cfg(target_os = "linux")] + #[test] + fn test_ensure_peer_executable_honors_server_privilege() { + let peer_exe_link = std::fs::read_link("/proc/1/exe"); + let result = super::ensure_peer_executable_matches_current_by_pid(1, "_uinput_mouse"); + match peer_exe_link { + Ok(peer_exe) => { + let peer = std::fs::canonicalize(&peer_exe).ok(); + let current = std::env::current_exe() + .ok() + .and_then(|exe| std::fs::canonicalize(exe).ok()); + // Only assert when the peer really is a different binary than this test. + if peer.is_some() && peer != current { + assert!( + result.is_err(), + "a readable but mismatched peer executable must be rejected" + ); + } + } + Err(err) if err.kind() == std::io::ErrorKind::PermissionDenied => { + if super::ipc_server_is_unprivileged() { + assert!( + result.is_ok(), + "an unprivileged server must defer to the uid gate when the peer executable is unreadable" + ); + } else { + assert!( + result.is_err(), + "a root server must stay fail-closed when the peer executable is unreadable" + ); + } + } + // No /proc, or PID 1 not inspectable for another reason: nothing to pin here. + Err(_) => {} + } + } }