Close hostile recovery and concurrency gaps
This commit is contained in:
parent
696dae610a
commit
3f9b1b3543
1 changed files with 306 additions and 113 deletions
|
|
@ -1070,12 +1070,12 @@ where
|
|||
return Ok(PidfsRecoveryMatch::BootMismatch);
|
||||
}
|
||||
let host_pid = identity.host_pid().get();
|
||||
let pidfd = open(host_pid)?;
|
||||
let pidfd = normalize_process_absence(open(host_pid))?;
|
||||
let observed = inspect(pidfd.as_fd(), current_boot)?;
|
||||
if observed != identity.authority() {
|
||||
return Err(io::Error::other("pidfs process authority mismatch"));
|
||||
}
|
||||
if start(host_pid)? != identity.start_time_ticks().get() {
|
||||
if normalize_process_absence(start(host_pid))? != identity.start_time_ticks().get() {
|
||||
return Err(io::Error::other("process start time mismatch"));
|
||||
}
|
||||
Ok(PidfsRecoveryMatch::Matched(RetainedProcess {
|
||||
|
|
@ -1084,6 +1084,16 @@ where
|
|||
}))
|
||||
}
|
||||
|
||||
fn normalize_process_absence<T>(result: io::Result<T>) -> io::Result<T> {
|
||||
result.map_err(|error| {
|
||||
if error.raw_os_error() == Some(rustix::io::Errno::NOENT.raw_os_error()) {
|
||||
io::Error::from_raw_os_error(rustix::io::Errno::SRCH.raw_os_error())
|
||||
} else {
|
||||
error
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// # Errors
|
||||
/// Refuses if arming fails or the exact parent changes during the recheck.
|
||||
pub fn arm_parent_death_and_recheck(
|
||||
|
|
@ -1745,6 +1755,50 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recovery_normalizes_vanished_proc_evidence_to_esrch() {
|
||||
let authority = PidfsProcessAuthorityV1 {
|
||||
boot_id: BootId::new([1; 16]),
|
||||
pidfs_st_dev: PidfsDeviceId::new(7),
|
||||
pidfs_st_ino: PidfsInodeId::new(9),
|
||||
};
|
||||
let identity = PidfsProcessIdentityV1::new(
|
||||
authority,
|
||||
HostPidLocator::new(41),
|
||||
ProcessStartTimeTicks::new(43),
|
||||
);
|
||||
for missing in ["open", "start"] {
|
||||
let result = match_recovery_process_with(
|
||||
identity,
|
||||
|| Ok(authority.boot_id),
|
||||
|_| {
|
||||
if missing == "open" {
|
||||
Err(io::Error::from_raw_os_error(
|
||||
rustix::io::Errno::NOENT.raw_os_error(),
|
||||
))
|
||||
} else {
|
||||
Ok(File::open("/dev/null").unwrap().into())
|
||||
}
|
||||
},
|
||||
|_, _| Ok(authority),
|
||||
|_| {
|
||||
if missing == "start" {
|
||||
Err(io::Error::from_raw_os_error(
|
||||
rustix::io::Errno::NOENT.raw_os_error(),
|
||||
))
|
||||
} else {
|
||||
Ok(43)
|
||||
}
|
||||
},
|
||||
)
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
result.raw_os_error(),
|
||||
Some(rustix::io::Errno::SRCH.raw_os_error())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recovery_action_reconciles_boot_without_process_action() {
|
||||
let mut old_boot = *read_boot_id().unwrap().as_bytes();
|
||||
|
|
|
|||
Loading…
Reference in a new issue