fix: exclude daemon's own sudo ancestor from password detection
When the daemon is started via `sudo vietc-daemon` from a terminal, is_sudo_process would see sudo( in the terminal's process tree and disable the engine, making all keystrokes pass through untransformed. Now is_sudo_process builds the daemon's ancestor PID chain and skips any sudo process that is an ancestor of the daemon itself.
This commit is contained in:
parent
4baa460562
commit
fcd465c2b0
1 changed files with 51 additions and 5 deletions
|
|
@ -831,18 +831,64 @@ fn log_password_detection(method: &str, context: &str) {
|
||||||
eprintln!("[vietc] Password field detected via {}: {}", method, context);
|
eprintln!("[vietc] Password field detected via {}: {}", method, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the given PID or any of its descendants is running sudo/passwd.
|
/// Walk up the process tree from `pid` to PID 1 and return all ancestor PIDs.
|
||||||
/// Uses pstree to scan the full process tree (handles any depth):
|
fn get_ancestor_pids(pid: u32) -> Vec<u32> {
|
||||||
/// terminal → shell → sudo → passwd
|
let mut ancestors = Vec::new();
|
||||||
/// gnome-terminal-server → gnome-terminal → bash → sudo
|
let mut current = pid;
|
||||||
|
loop {
|
||||||
|
ancestors.push(current);
|
||||||
|
let path = format!("/proc/{}/status", current);
|
||||||
|
let content = match std::fs::read_to_string(&path) {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(_) => break,
|
||||||
|
};
|
||||||
|
let ppid = match content
|
||||||
|
.lines()
|
||||||
|
.find(|l| l.starts_with("PPid:"))
|
||||||
|
.and_then(|l| l.split_whitespace().nth(1))
|
||||||
|
.and_then(|s| s.parse::<u32>().ok())
|
||||||
|
{
|
||||||
|
Some(0) | None => break,
|
||||||
|
Some(p) => p,
|
||||||
|
};
|
||||||
|
if ppid == current {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = ppid;
|
||||||
|
}
|
||||||
|
ancestors
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the given PID or any of its descendants is running a password
|
||||||
|
/// prompt (sudo, passwd, pkexec). Excludes the daemon's own ancestor chain
|
||||||
|
/// so that running `sudo vietc-daemon` from the same terminal doesn't cause
|
||||||
|
/// a false positive.
|
||||||
fn is_sudo_process(pid: u32) -> bool {
|
fn is_sudo_process(pid: u32) -> bool {
|
||||||
|
// Build the daemon's ancestor PID chain to exclude self from detection
|
||||||
|
let daemon_pid = unsafe { libc::getpid() as u32 };
|
||||||
|
let daemon_ancestors = get_ancestor_pids(daemon_pid);
|
||||||
|
|
||||||
if let Ok(output) = Command::new("pstree")
|
if let Ok(output) = Command::new("pstree")
|
||||||
.args(["-p", &pid.to_string()])
|
.args(["-p", &pid.to_string()])
|
||||||
.output()
|
.output()
|
||||||
{
|
{
|
||||||
let tree = String::from_utf8_lossy(&output.stdout);
|
let tree = String::from_utf8_lossy(&output.stdout);
|
||||||
for target in &["sudo(", "passwd(", "pkexec("] {
|
for target in &["sudo(", "passwd(", "pkexec("] {
|
||||||
if tree.contains(target) {
|
let mut start = 0;
|
||||||
|
while let Some(pos) = tree[start..].find(target) {
|
||||||
|
let abs_pos = start + pos;
|
||||||
|
let after = &tree[abs_pos + target.len()..];
|
||||||
|
let found_pid = after
|
||||||
|
.split(')')
|
||||||
|
.next()
|
||||||
|
.and_then(|s| s.parse::<u32>().ok());
|
||||||
|
// Skip if this PID is the daemon's own ancestor (e.g. `sudo vietc-daemon`)
|
||||||
|
if let Some(p) = found_pid {
|
||||||
|
if target == &"sudo(" && daemon_ancestors.contains(&p) {
|
||||||
|
start = abs_pos + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue