use libseccomp::ScmpNotifResp;
use nix::errno::Errno;
#[cfg(feature = "kcov")]
use crate::kcov::abi::kcov_ioctl;
use crate::{
ioctl::Ioctl,
log::get_ioctl_log,
log_enabled,
req::UNotifyEventRequest,
sandbox::{Action, Capability},
syslog::LogLevel,
warn,
};
#[expect(clippy::cognitive_complexity)]
pub(crate) fn sys_ioctl(request: UNotifyEventRequest) -> ScmpNotifResp {
syscall_handler!(request, |request: UNotifyEventRequest| {
let req = request.scmpreq;
let sandbox = request.get_sandbox();
#[cfg(feature = "kcov")]
{
let arg = crate::req::SysArg {
dirfd: Some(0),
..Default::default()
};
let (path, _, _) = request.read_path(&sandbox, arg)?;
if path.is_memory_fd() && path.abs().is_kcov_mfd() {
return kcov_ioctl(&request);
}
}
#[expect(clippy::cast_possible_truncation)]
let arg = req.data.args[1] as Ioctl;
let cap = Capability::CAP_IOCTL;
let action = sandbox.check_ioctl(arg, req.data.arch);
let filter = action == Action::Filter;
if !filter && action >= Action::Warn && log_enabled!(LogLevel::Warn) {
let log_scmp = sandbox.log_scmp();
let ctl = get_ioctl_log(arg, req.data.arch, sandbox.log_ioctl())
.ok()
.flatten();
let grp = cap.to_string().to_ascii_lowercase();
let tip = if let Some(name) = ctl.as_ref().and_then(|ctl| ctl.first()) {
format!("configure `allow/{grp}+{name}'")
} else {
format!("configure `allow/{grp}+{arg:#x}'")
};
if log_scmp {
warn!("ctx": "access", "cap": cap, "act": action,
"sys": "ioctl", "ctl": ctl, "tip": tip,
"req": &request);
} else {
warn!("ctx": "access", "cap": cap, "act": action,
"sys": "ioctl", "ctl": ctl, "tip": tip,
"pid": request.scmpreq.pid);
}
}
drop(sandbox);
match action {
Action::Allow | Action::Warn => {
Ok(unsafe { request.continue_syscall() })
}
Action::Filter | Action::Deny => Err(Errno::EACCES),
Action::Panic => panic!(),
Action::Exit => std::process::exit(libc::EACCES),
action => {
let _ = request.kill(action);
Err(Errno::EACCES)
}
}
})
}