Harden session terminal release authority
This commit is contained in:
parent
51ff63a3aa
commit
4dc5daa57b
1 changed files with 920 additions and 156 deletions
|
|
@ -57,15 +57,69 @@ fn run_session_exec(arguments: &[OsString]) -> io::Result<()> {
|
|||
}
|
||||
|
||||
fn report_session_identity(arguments: &[OsString]) -> io::Result<()> {
|
||||
let pid = match arguments {
|
||||
[pid] => pid
|
||||
match arguments {
|
||||
[pid] => report_process_identity(parse_positive_pid(pid)?),
|
||||
[mode, group] if mode == "--group" => report_group_presence(parse_positive_pid(group)?),
|
||||
_ => Err(io::Error::other("session identity query is invalid")),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_positive_pid(value: &OsStr) -> io::Result<u32> {
|
||||
value
|
||||
.to_str()
|
||||
.and_then(|value| value.parse::<u32>().ok())
|
||||
.filter(|value| *value > 0)
|
||||
.ok_or_else(|| io::Error::other("session identity number is invalid"))
|
||||
}
|
||||
|
||||
fn report_process_identity(pid: u32) -> io::Result<()> {
|
||||
let Some((observed_pid, start_ticks, group)) = read_process_identity(pid)? else {
|
||||
println!("absent");
|
||||
return Ok(());
|
||||
};
|
||||
println!("{observed_pid} {start_ticks} {group}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn report_group_presence(group: u32) -> io::Result<()> {
|
||||
println!(
|
||||
"{}",
|
||||
if group_is_present_except(group, std::process::id())? {
|
||||
"present"
|
||||
} else {
|
||||
"absent"
|
||||
}
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn group_is_present_except(group: u32, observer: u32) -> io::Result<bool> {
|
||||
for entry in std::fs::read_dir("/proc")? {
|
||||
let entry = entry?;
|
||||
let Some(pid) = entry
|
||||
.file_name()
|
||||
.to_str()
|
||||
.and_then(|value| value.parse::<u32>().ok())
|
||||
.filter(|pid| *pid > 0)
|
||||
.ok_or_else(|| io::Error::other("session identity PID is invalid"))?,
|
||||
_ => return Err(io::Error::other("session identity requires one PID")),
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
if pid == observer {
|
||||
continue;
|
||||
}
|
||||
if read_process_identity(pid)?.is_some_and(|(_, _, observed_group)| observed_group == group)
|
||||
{
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn read_process_identity(pid: u32) -> io::Result<Option<(u32, u64, u32)>> {
|
||||
let stat = match std::fs::read_to_string(format!("/proc/{pid}/stat")) {
|
||||
Ok(stat) => stat,
|
||||
Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(None),
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let stat = std::fs::read_to_string(format!("/proc/{pid}/stat"))?;
|
||||
let close = stat
|
||||
.rfind(')')
|
||||
.ok_or_else(|| io::Error::other("guest process stat is malformed"))?;
|
||||
|
|
@ -82,8 +136,7 @@ fn report_session_identity(arguments: &[OsString]) -> io::Result<()> {
|
|||
.get(19)
|
||||
.and_then(|value| value.parse::<u64>().ok())
|
||||
.ok_or_else(|| io::Error::other("guest process stat start is malformed"))?;
|
||||
println!("{observed_pid} {start_ticks} {group}");
|
||||
Ok(())
|
||||
Ok(Some((observed_pid, start_ticks, group)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -125,4 +178,11 @@ mod tests {
|
|||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_presence_is_independent_of_a_designated_leader() {
|
||||
let (_, _, group) = read_process_identity(std::process::id()).unwrap().unwrap();
|
||||
assert!(group_is_present_except(group, u32::MAX).unwrap());
|
||||
assert!(!group_is_present_except(u32::MAX, u32::MAX).unwrap());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue