#![allow(missing_docs)]
use core::pin::Pin;
use core::task::Context;
use core::task::Poll;
use std::io;
use std::os::unix::io::AsRawFd;
use syscalls::Errno;
use tokio::io::Interest;
use tokio::io::unix::AsyncFd;
use crate::fd::Fd;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct seccomp_data {
pub nr: i32,
pub arch: u32,
pub instruction_pointer: u64,
pub args: [u64; 6],
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct seccomp_notif_sizes {
seccomp_notif: u16,
seccomp_notif_resp: u16,
seccomp_data: u16,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct seccomp_notif {
pub id: u64,
pub pid: u32,
pub flags: u32,
pub data: seccomp_data,
}
pub const SECCOMP_USER_NOTIF_FLAG_CONTINUE: u32 = 1u32 << 0;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct seccomp_notif_resp {
pub id: u64,
pub val: i64,
pub error: i32,
pub flags: u32,
}
pub const SECCOMP_ADDFD_FLAG_SETFD: u32 = 1u32 << 0;
pub const SECCOMP_ADDFD_FLAG_SEND: u32 = 1u32 << 1;
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct seccomp_notif_addfd {
pub id: u64,
pub flags: u32,
pub srcfd: u32,
pub newfd: u32,
pub newfd_flags: u32,
}
pub const SECCOMP_IOCTL_NOTIF_RECV: u64 = 0xc0502100;
pub const SECCOMP_IOCTL_NOTIF_SEND: u64 = 0xc0182101;
pub const SECCOMP_IOCTL_NOTIF_ID_VALID: u64 = 0x40082102;
pub const SECCOMP_IOCTL_NOTIF_ADDFD: u64 = 0x40182103;
#[derive(Debug)]
pub struct SeccompNotif(AsyncFd<Fd>);
impl SeccompNotif {
pub(crate) fn new(fd: Fd) -> Result<Self, Errno> {
fd.set_nonblocking()?;
Ok(Self(
AsyncFd::with_interest(fd, Interest::READABLE).unwrap(),
))
}
pub fn poll_recv(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<io::Result<seccomp_notif>> {
loop {
let mut guard = futures::ready!(self.0.poll_read_ready_mut(cx))?;
match guard.try_io(|inner| seccomp_notif_recv(inner.get_mut())) {
Ok(result) => return Poll::Ready(result),
Err(_would_block) => continue,
}
}
}
pub fn send(&mut self, response: &seccomp_notif_resp) -> Result<(), Errno> {
Errno::result(unsafe {
libc::ioctl(
self.0.as_raw_fd(),
SECCOMP_IOCTL_NOTIF_SEND,
response as *const _,
)
})
.map(drop)
}
pub fn id_valid(&mut self, id: u64) -> Result<(), Errno> {
Errno::result(unsafe {
libc::ioctl(
self.0.as_raw_fd(),
SECCOMP_IOCTL_NOTIF_ID_VALID,
&id as *const _,
)
})
.map(drop)
}
pub fn addfd(&mut self, addfd: &seccomp_notif_addfd) -> Result<(), Errno> {
Errno::result(unsafe {
libc::ioctl(
self.0.as_raw_fd(),
SECCOMP_IOCTL_NOTIF_ADDFD,
addfd as *const _,
)
})
.map(drop)
}
}
impl futures::stream::Stream for SeccompNotif {
type Item = io::Result<seccomp_notif>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.poll_recv(cx).map(Some)
}
}
fn seccomp_notif_recv(fd: &Fd) -> io::Result<seccomp_notif> {
let mut response = core::mem::MaybeUninit::<seccomp_notif>::zeroed();
match Errno::result(unsafe {
libc::ioctl(
fd.as_raw_fd(),
SECCOMP_IOCTL_NOTIF_RECV,
&mut response as *mut _,
)
}) {
Err(Errno::EINTR) | Err(Errno::ENOENT) => Err(Errno::EAGAIN),
result => result,
}?;
Ok(unsafe { response.assume_init() })
}