use std::sync::{Arc, RwLock};
use nix::{sys::signal::Signal, unistd::Pid};
use crate::{
compat::{readlinkat, WaitStatus},
confine::{is_coredump, SydNotifResp},
error,
fd::PROC_FILE,
info,
path::XPathBuf,
sandbox::{Sandbox, SandboxGuard},
workers::WorkerCache,
};
#[expect(clippy::cognitive_complexity)]
pub(crate) fn sysevent_exit(
pid: Pid,
status: WaitStatus,
wait_all: bool,
cache: &Arc<WorkerCache>,
sandbox: &Arc<RwLock<Sandbox>>,
) -> Option<SydNotifResp> {
#[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 my_sandbox = SandboxGuard::Read(sandbox.read().unwrap_or_else(|err| err.into_inner()));
let is_child = pid == my_sandbox.get_child_pid();
let has_segvguard = !my_sandbox.get_segvguard_expiry().is_zero();
let segvguard_expiry = my_sandbox.get_segvguard_expiry();
let segvguard_suspension = my_sandbox.get_segvguard_suspension();
let segvguard_maxcrashes = my_sandbox.get_segvguard_maxcrashes();
drop(my_sandbox);
if has_segvguard && !(is_child && !wait_all) {
let sig = match status {
WaitStatus::Signaled(_, sig, true) => Some(sig),
WaitStatus::Signaled(_, sig, _) if is_coredump(sig) => Some(sig),
_ => 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 Some(SydNotifResp::Cont { pid, signal: None }),
};
let (was_suspended, is_suspended, num_crashes) = match cache.add_segvguard_crash(
&path,
segvguard_expiry,
segvguard_suspension,
segvguard_maxcrashes,
) {
Ok(result) => result,
Err(_) => return Some(SydNotifResp::Cont { pid, signal: None }),
};
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);
}
}
}
#[cfg(feature = "kcov")]
{
crate::kcov_edge!();
let _ = crate::kcov::abi::kcov_exit_for(pid);
}
Some(SydNotifResp::Cont { pid, signal: None })
}