| 82 | /// to read `/proc/<pid>/exe` (e.g. same user, or `CAP_SYS_PTRACE`). |
| 83 | #[cfg(target_os = "linux")] |
| 84 | pub fn binary_path(pid: i32) -> Result<PathBuf> { |
| 85 | use std::ffi::OsString; |
| 86 | use std::io::ErrorKind; |
| 87 | use std::os::unix::ffi::{OsStrExt, OsStringExt}; |
| 88 | |
| 89 | const DELETED_SUFFIX: &[u8] = b" (deleted)"; |
| 90 | |
| 91 | let link = format!("/proc/{pid}/exe"); |
| 92 | let target = std::fs::read_link(&link).map_err(|e| { |
| 93 | miette::miette!( |
| 94 | "Failed to read /proc/{pid}/exe: {e}. \ |
| 95 | Cannot determine binary identity — denying request. \ |
| 96 | Hint: the proxy may need CAP_SYS_PTRACE or to run as the same user." |
| 97 | ) |
| 98 | })?; |
| 99 | |
| 100 | // Only strip when the raw readlink target cannot be stat'd and its bytes |
| 101 | // end with the kernel-added suffix. This preserves live executables whose |
| 102 | // basename legitimately ends with " (deleted)" and handles non-UTF-8 |
| 103 | // filenames correctly. |
| 104 | let raw_target_missing = |
| 105 | matches!(std::fs::metadata(&target), Err(err) if err.kind() == ErrorKind::NotFound); |
| 106 | |
| 107 | let bytes = target.as_os_str().as_bytes(); |
| 108 | if raw_target_missing && bytes.ends_with(DELETED_SUFFIX) { |
| 109 | let stripped = bytes[..bytes.len() - DELETED_SUFFIX.len()].to_vec(); |
| 110 | return Ok(PathBuf::from(OsString::from_vec(stripped))); |
| 111 | } |
| 112 | |
| 113 | Ok(target) |
| 114 | } |
| 115 | |
| 116 | /// Resolve the binary path of the TCP peer inside a sandbox network namespace. |
| 117 | /// |