Kill the child processes at once on a second interrupt during the grace period

This commit is contained in:
2026-11-04 02:50:35 +01:00
parent 5389ac97ac
commit 599d86ccbf
4 changed files with 61 additions and 5 deletions
+1 -1
View File
@@ -114,6 +114,6 @@ pub fn run(config: SandboxConfig) -> Result<ExitStatus, SandboxError> {
// bwrap ignores them: its death would SIGKILL the entrypoint through --die-with-parent.
let bwrap_process = bwrap.spawn(signal_forwarder.ignore_forwarded_signals())?;
let status = signal_forwarder.forward_until_exit(&bwrap_process)?;
process_tree::terminate_and_reap_all(CLEANUP_GRACE_PERIOD)?;
process_tree::terminate_and_reap_all(CLEANUP_GRACE_PERIOD, signals::has_pending_interrupt)?;
Ok(status)
}
+9 -4
View File
@@ -16,10 +16,13 @@ pub fn become_subreaper() -> io::Result<()> {
Ok(prctl::set_child_subreaper(true)?)
}
pub fn terminate_and_reap_all(grace_period: Duration) -> io::Result<()> {
pub fn terminate_and_reap_all(
grace_period: Duration,
should_stop_waiting: impl Fn() -> bool,
) -> io::Result<()> {
signal_all_children(&[Signal::TERM, Signal::CONT]);
if reap_until(Instant::now() + grace_period)? {
if reap_until(Instant::now() + grace_period, should_stop_waiting)? {
return Ok(());
}
@@ -100,11 +103,13 @@ fn send_signals(pidfd: &OwnedFd, signals: &[Signal]) {
}
}
fn reap_until(deadline: Instant) -> io::Result<bool> {
fn reap_until(deadline: Instant, should_stop_waiting: impl Fn() -> bool) -> io::Result<bool> {
loop {
match process::wait(WaitOptions::NOHANG) {
Ok(Some(_)) => {}
Ok(None) if Instant::now() < deadline => thread::sleep(REAP_POLL_INTERVAL),
Ok(None) if Instant::now() < deadline && !should_stop_waiting() => {
thread::sleep(REAP_POLL_INTERVAL)
}
Ok(None) => return Ok(false),
Err(Errno::CHILD) => return Ok(true),
Err(e) => return Err(e.into()),
+9
View File
@@ -177,6 +177,15 @@ fn reap_until_exit_of(child: Pid) -> io::Result<Option<ExitStatus>> {
}
}
pub fn has_pending_interrupt() -> bool {
let interrupt = SigSet::from(Signal::SIGINT);
let no_wait = libc::timespec {
tv_sec: 0,
tv_nsec: 0,
};
unsafe { libc::sigtimedwait(interrupt.as_ref(), ptr::null_mut(), &no_wait) == libc::SIGINT }
}
pub fn exit_with_status(status: ExitStatus) -> ! {
match status.signal() {
Some(number) => kill_self_with(number),