use std::sync::{Arc, RwLock};
use nix::{sys::signal::Signal, unistd::Pid};
use crate::{
compat::WaitStatus,
confine::is_coredump,
error,
fd::PROC_FILE,
fs::readlinkat,
info,
path::XPathBuf,
ptrace::{ptrace_cont, ptrace_getevent},
sandbox::{Sandbox, SandboxGuard},
workers::WorkerCache,
};
#[expect(clippy::cognitive_complexity)]
pub(crate) fn sysevent_exit(pid: Pid, cache: &Arc<WorkerCache>, sandbox: &Arc<RwLock<Sandbox>>) {
#[cfg(feature = "kcov")]
{
crate::kcov::abi::kcov_attach(pid);
crate::kcov::abi::kcov_set_syscall(libc::SYS_exit);
let _ = crate::kcov::abi::kcov_enter_for(pid);
crate::kcov_edge!();
}
let mut my_sandbox = SandboxGuard::Read(sandbox.read().unwrap_or_else(|err| err.into_inner()));
let has_segvguard = !my_sandbox.get_segvguard_expiry().is_zero();
drop(my_sandbox);
if has_segvguard {
let sig = match ptrace_getevent(pid) {
Ok(status) => {
#[expect(clippy::cast_possible_truncation)]
match WaitStatus::from_raw(pid, status as i32) {
WaitStatus::Signaled(_, sig, true) => Some(sig),
WaitStatus::Signaled(_, sig, _) if is_coredump(sig) => Some(sig),
_ => None, }
}
Err(_) => None, };
if let Some(sig) = sig {
let path = match XPathBuf::from_exe(pid).and_then(|exe| readlinkat(PROC_FILE(), &exe)) {
Ok(path) => path,
Err(_) => return,
};
my_sandbox =
SandboxGuard::Write(sandbox.write().unwrap_or_else(|err| err.into_inner()));
let (was_suspended, is_suspended, num_crashes) = my_sandbox.add_segvguard_crash(&path);
drop(my_sandbox);
let signal = Signal::try_from(sig).unwrap_or(Signal::SIGKILL);
let crashes = if num_crashes > 1 { "crashes" } else { "crash" };
if is_suspended {
error!("ctx": "segvguard",
"msg": format!("suspending after {signal} due to {num_crashes} {crashes}"),
"tip": "increase `segvguard/maxcrashes'",
"pid": pid.as_raw(), "path": path, "sig": sig);
} else {
info!("ctx": "segvguard",
"msg": format!("{num_crashes} {crashes} recorded after {signal}{}",
if was_suspended { " (suspended)" } else { "" }),
"pid": pid.as_raw(), "path": path, "sig": sig);
}
}
}
cache.del_tid(pid);
#[cfg(feature = "kcov")]
{
crate::kcov_edge!();
let _ = crate::kcov::abi::kcov_exit_for(pid);
}
let _ = ptrace_cont(pid, None);
}