Skip to content

Commit 6028f0b

Browse files
Check if process is system on linux (mitmproxy#205)
* check if process is system * reuse code across macos_list.rs and linux_list.rs * nits * modify is_system heuristic * [autofix.ci] apply automated fixes * use uid to check if process is system * [autofix.ci] apply automated fixes * fix * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * fix * [autofix.ci] apply automated fixes * restructure macos_visible_windows * .deref() uids for comparison --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 69bc397 commit 6028f0b

File tree

4 files changed

+166
-187
lines changed

4 files changed

+166
-187
lines changed

src/processes/linux_list.rs

Lines changed: 0 additions & 55 deletions
This file was deleted.

src/processes/macos_list.rs

Lines changed: 0 additions & 122 deletions
This file was deleted.

src/processes/mod.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
pub use image;
22
use std::path::PathBuf;
33

4-
#[cfg(target_os = "macos")]
5-
mod macos_list;
6-
#[cfg(target_os = "macos")]
7-
pub use self::macos_list::active_executables;
4+
#[cfg(any(target_os = "linux", target_os = "macos"))]
5+
mod nix_list;
6+
#[cfg(any(target_os = "linux", target_os = "macos"))]
7+
pub use self::nix_list::active_executables;
88

99
#[cfg(windows)]
1010
mod windows_list;
@@ -13,11 +13,6 @@ pub use self::windows_list::active_executables;
1313
#[cfg(windows)]
1414
pub use self::windows_list::get_process_name;
1515

16-
#[cfg(target_os = "linux")]
17-
mod linux_list;
18-
#[cfg(target_os = "linux")]
19-
pub use self::linux_list::active_executables;
20-
2116
#[cfg(target_os = "macos")]
2217
mod macos_icons;
2318
#[cfg(target_os = "macos")]
@@ -44,7 +39,7 @@ pub static ICON_CACHE: once_cell::sync::Lazy<std::sync::Mutex<IconCache>> =
4439

4540
pub mod bench {
4641
#[cfg(target_os = "macos")]
47-
pub use super::macos_list::visible_windows;
42+
pub use super::nix_list::visible_windows;
4843
#[cfg(windows)]
4944
pub use super::windows_list::visible_windows;
5045

src/processes/nix_list.rs

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
use crate::intercept_conf::PID;
2+
use crate::processes::{ProcessInfo, ProcessList};
3+
use anyhow::Result;
4+
use std::collections::hash_map::Entry;
5+
use std::collections::{HashMap, HashSet};
6+
use std::path::PathBuf;
7+
use sysinfo::{Process, ProcessRefreshKind, ProcessesToUpdate, System, UpdateKind};
8+
9+
#[cfg(target_os = "linux")]
10+
use std::ops::Deref;
11+
12+
#[cfg(target_os = "macos")]
13+
use macos_visible_windows::macos_visible_windows;
14+
15+
pub fn active_executables() -> Result<ProcessList> {
16+
let mut executables: HashMap<PathBuf, ProcessInfo> = HashMap::new();
17+
let visible = visible_windows()?;
18+
let mut sys = System::new();
19+
sys.refresh_processes_specifics(
20+
ProcessesToUpdate::All,
21+
true,
22+
ProcessRefreshKind::nothing()
23+
.with_exe(UpdateKind::OnlyIfNotSet)
24+
.with_user(UpdateKind::OnlyIfNotSet),
25+
);
26+
for (pid, process) in sys.processes() {
27+
// process.exe() will return empty path if there was an error while trying to read /proc/<pid>/exe.
28+
if let Some(path) = process.exe() {
29+
let pid = pid.as_u32();
30+
let executable = path.to_path_buf();
31+
match executables.entry(executable) {
32+
Entry::Occupied(mut e) => {
33+
let process_info = e.get();
34+
if !process_info.is_visible && visible.contains(&pid) {
35+
e.get_mut().is_visible = true;
36+
}
37+
}
38+
Entry::Vacant(e) => {
39+
let executable = e.key().clone();
40+
// .file_name() returns `None` if the path terminates in `..`
41+
// We use the absolute path in such a case.
42+
let display_name = path
43+
.file_name()
44+
.unwrap_or(path.as_os_str())
45+
.to_string_lossy()
46+
.to_string();
47+
let is_system = is_system(process);
48+
let is_visible = visible.contains(&pid);
49+
e.insert(ProcessInfo {
50+
executable,
51+
display_name,
52+
is_visible,
53+
is_system,
54+
});
55+
}
56+
}
57+
}
58+
}
59+
Ok(executables.into_values().collect())
60+
}
61+
62+
pub fn visible_windows() -> Result<HashSet<PID>> {
63+
#[cfg(target_os = "macos")]
64+
return macos_visible_windows();
65+
66+
#[cfg(target_os = "linux")]
67+
// Finding visible windows is less useful on Linux, where more applications tend to be CLI-based.
68+
// So we skip all the X11/Wayland complexity.
69+
return Ok(HashSet::new());
70+
}
71+
72+
fn is_system(process: &Process) -> bool {
73+
#[cfg(target_os = "macos")]
74+
return process
75+
.exe()
76+
.map(|path| path.starts_with("/System/"))
77+
.unwrap_or(false);
78+
79+
#[cfg(target_os = "linux")]
80+
return process
81+
.user_id()
82+
.map(|uid| *uid.deref() < 1000)
83+
.unwrap_or(false);
84+
}
85+
86+
#[cfg(target_os = "macos")]
87+
mod macos_visible_windows {
88+
use crate::intercept_conf::PID;
89+
use anyhow::Result;
90+
use cocoa::base::nil;
91+
use cocoa::foundation::NSString;
92+
use core_foundation::number::{kCFNumberSInt32Type, CFNumberGetValue, CFNumberRef};
93+
use core_graphics::display::{
94+
kCGNullWindowID, kCGWindowListExcludeDesktopElements, kCGWindowListOptionOnScreenOnly,
95+
CFArrayGetCount, CFArrayGetValueAtIndex, CFDictionaryGetValueIfPresent, CFDictionaryRef,
96+
CGWindowListCopyWindowInfo,
97+
};
98+
use std::collections::HashSet;
99+
use std::ffi::c_void;
100+
101+
pub fn macos_visible_windows() -> Result<HashSet<PID>> {
102+
let mut pids: HashSet<PID> = HashSet::new();
103+
unsafe {
104+
let windows_info_list = CGWindowListCopyWindowInfo(
105+
kCGWindowListOptionOnScreenOnly + kCGWindowListExcludeDesktopElements,
106+
kCGNullWindowID,
107+
);
108+
let count = CFArrayGetCount(windows_info_list);
109+
110+
for i in 0..count - 1 {
111+
let dic_ref = CFArrayGetValueAtIndex(windows_info_list, i);
112+
let key = NSString::alloc(nil).init_str("kCGWindowOwnerPID");
113+
let mut pid: *const c_void = std::ptr::null_mut();
114+
115+
if CFDictionaryGetValueIfPresent(
116+
dic_ref as CFDictionaryRef,
117+
key as *const c_void,
118+
&mut pid,
119+
) != 0
120+
{
121+
let pid_cf_ref = pid as CFNumberRef;
122+
let mut pid: i32 = 0;
123+
if CFNumberGetValue(
124+
pid_cf_ref,
125+
kCFNumberSInt32Type,
126+
&mut pid as *mut i32 as *mut c_void,
127+
) {
128+
pids.insert(pid as u32);
129+
}
130+
}
131+
}
132+
Ok(pids)
133+
}
134+
}
135+
}
136+
137+
#[cfg(test)]
138+
mod tests {
139+
use super::*;
140+
141+
#[test]
142+
fn process_list() {
143+
let lst = active_executables().unwrap();
144+
assert!(!lst.is_empty());
145+
146+
for proc in &lst {
147+
if !proc.is_visible {
148+
dbg!(&proc.display_name);
149+
}
150+
}
151+
dbg!(lst.len());
152+
}
153+
154+
#[cfg(target_os = "macos")]
155+
#[test]
156+
fn visible_windows_list() {
157+
let open_windows_pids = visible_windows().unwrap();
158+
assert!(!open_windows_pids.is_empty());
159+
dbg!(open_windows_pids.len());
160+
}
161+
}

0 commit comments

Comments
 (0)