use super::alloc::{Alloc, Allocator, Collect, Commit, Committer};
use super::call::kind;
use super::syscall::types::{MremapFlags, SockaddrInput, SockaddrOutput, SockoptInput};
use super::{enarxcall, gdbcall, syscall, Call, Platform, ThreadLocalStorage, SIGRTMAX};
use crate::item::enarxcall::sgx;
use crate::item::syscall::sigaction;
use crate::libc::{
clockid_t, epoll_event, gid_t, mode_t, off_t, pid_t, pollfd, sigset_t, stack_t, stat, timespec,
uid_t, utsname, Ioctl, SYS_accept, SYS_accept4, SYS_arch_prctl, SYS_bind, SYS_brk,
SYS_clock_getres, SYS_clock_gettime, SYS_close, SYS_connect, SYS_dup, SYS_dup2, SYS_dup3,
SYS_epoll_create1, SYS_epoll_ctl, SYS_epoll_pwait, SYS_epoll_wait, SYS_eventfd2, SYS_exit,
SYS_exit_group, SYS_fcntl, SYS_fstat, SYS_getegid, SYS_geteuid, SYS_getgid, SYS_getpid,
SYS_getrandom, SYS_getsockname, SYS_getuid, SYS_ioctl, SYS_listen, SYS_madvise, SYS_mmap,
SYS_mprotect, SYS_mremap, SYS_munmap, SYS_nanosleep, SYS_open, SYS_poll, SYS_read,
SYS_readlink, SYS_readv, SYS_recvfrom, SYS_rt_sigaction, SYS_rt_sigprocmask, SYS_sendto,
SYS_set_tid_address, SYS_setsockopt, SYS_sigaltstack, SYS_socket, SYS_sync, SYS_uname,
SYS_write, SYS_writev, EFAULT, EINVAL, ENOSYS, ENOTSUP, FIONBIO, FIONREAD, MAP_ANONYMOUS,
MAP_PRIVATE, MREMAP_DONTUNMAP, MREMAP_FIXED, MREMAP_MAYMOVE, PROT_EXEC, PROT_READ, PROT_WRITE,
};
use crate::{item, Result};
use core::arch::x86_64::CpuidResult;
use core::ffi::{c_int, c_size_t, c_uint, c_ulong, c_void};
use core::mem::size_of;
use core::ptr::NonNull;
use core::slice;
pub trait Handler {
fn sally(&mut self) -> Result<()>;
fn block(&self) -> &[usize];
fn block_mut(&mut self) -> &mut [usize];
fn thread_local_storage(&mut self) -> &mut ThreadLocalStorage;
#[inline]
fn execute<'a, K: kind::Kind, T: Call<'a, K>>(&mut self, call: T) -> Result<T::Collected> {
let mut alloc = Alloc::new(self.block_mut()).stage();
let ((call, len), mut end_ref) =
alloc.reserve_input(|alloc| alloc.section(|alloc| call.stage(alloc)))?;
let alloc = alloc.commit();
let call = call.commit(&alloc);
let alloc = if len > 0 {
end_ref.copy_from(
&alloc,
item::Header {
kind: item::Kind::End,
size: 0,
},
);
let collect = alloc.sally();
self.sally()?;
collect(self.block())?
} else {
alloc.collect()
};
Ok(call.collect(&alloc))
}
#[inline]
fn attacked(&mut self) -> ! {
loop {
let _ = self.exit(1);
}
}
#[inline]
fn accept<'a>(
&mut self,
sockfd: c_int,
addr: Option<impl Into<SockaddrOutput<'a>>>,
) -> Result<c_int> {
self.execute(syscall::Accept { sockfd, addr })?
}
#[inline]
fn accept4<'a>(
&mut self,
sockfd: c_int,
addr: Option<impl Into<SockaddrOutput<'a>>>,
flags: c_int,
) -> Result<c_int> {
self.execute(syscall::Accept4 {
sockfd,
addr,
flags,
})?
}
fn arch_prctl(&mut self, platform: &impl Platform, code: c_int, addr: c_ulong) -> Result<()>;
#[inline]
fn bind<'a>(&mut self, sockfd: c_int, addr: impl Into<SockaddrInput<'a>>) -> Result<()> {
self.execute(syscall::Bind { sockfd, addr })?
}
fn brk(
&mut self,
platform: &impl Platform,
addr: Option<NonNull<c_void>>,
) -> Result<NonNull<c_void>>;
#[inline]
fn clock_getres(&mut self, clockid: clockid_t, res: Option<&mut timespec>) -> Result<()> {
self.execute(syscall::ClockGetres { clockid, res })?
}
#[inline]
fn clock_gettime(&mut self, clockid: clockid_t, tp: &mut timespec) -> Result<()> {
self.execute(syscall::ClockGettime { clockid, tp })?
}
#[inline]
fn close(&mut self, fd: c_int) -> Result<()> {
self.execute(syscall::Close { fd })?
}
#[inline]
fn connect<'a>(&mut self, sockfd: c_int, addr: impl Into<SockaddrInput<'a>>) -> Result<()> {
self.execute(syscall::Connect { sockfd, addr })?
}
#[inline]
fn dup(&mut self, oldfd: c_int) -> Result<()> {
self.execute(syscall::Dup { oldfd })?
}
#[inline]
fn dup2(&mut self, oldfd: c_int, newfd: c_int) -> Result<()> {
self.execute(syscall::Dup2 { oldfd, newfd })?
}
#[inline]
fn dup3(&mut self, oldfd: c_int, newfd: c_int, flags: c_int) -> Result<()> {
self.execute(syscall::Dup3 {
oldfd,
newfd,
flags,
})?
}
#[inline]
fn epoll_create1(&mut self, flags: c_int) -> Result<c_int> {
self.execute(syscall::EpollCreate1 { flags })?
}
#[inline]
fn epoll_ctl(&mut self, epfd: c_int, op: c_int, fd: c_int, event: &epoll_event) -> Result<()> {
self.execute(syscall::EpollCtl {
epfd,
op,
fd,
event,
})?
}
#[inline]
fn epoll_wait(
&mut self,
epfd: c_int,
events: &mut [epoll_event],
timeout: c_int,
) -> Result<c_int> {
self.execute(syscall::EpollWait {
epfd,
events,
timeout,
})?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn epoll_pwait(
&mut self,
epfd: c_int,
events: &mut [epoll_event],
timeout: c_int,
sigmask: &sigset_t,
) -> Result<c_int> {
self.execute(syscall::EpollPwait {
epfd,
events,
timeout,
sigmask,
})?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn eventfd2(&mut self, initval: c_int, flags: c_int) -> Result<c_int> {
self.execute(syscall::Eventfd2 { initval, flags })?
}
#[inline]
fn exit(&mut self, status: c_int) -> Result<()> {
self.execute(syscall::Exit { status })??;
self.attacked()
}
#[inline]
fn exit_group(&mut self, status: c_int) -> Result<()> {
self.execute(syscall::ExitGroup { status })??;
self.attacked()
}
#[inline]
fn fcntl(&mut self, fd: c_int, cmd: c_int, arg: c_int) -> Result<c_int> {
self.execute(syscall::Fcntl { fd, cmd, arg })?
}
#[inline]
fn fstat(&mut self, fd: c_int, statbuf: &mut stat) -> Result<()> {
self.execute(syscall::Fstat { fd, statbuf })?
}
#[inline]
fn getegid(&mut self) -> Result<gid_t> {
self.execute(syscall::Getegid)
}
#[inline]
fn geteuid(&mut self) -> Result<uid_t> {
self.execute(syscall::Geteuid)
}
#[inline]
fn getgid(&mut self) -> Result<gid_t> {
self.execute(syscall::Getgid)
}
#[inline]
fn getpid(&mut self) -> Result<pid_t> {
self.execute(syscall::Getpid)
}
#[inline]
fn getrandom(&mut self, buf: &mut [u8], flags: c_uint) -> Result<c_size_t> {
self.execute(syscall::Getrandom { buf, flags })?
}
#[inline]
fn getsockname<'a>(
&mut self,
sockfd: c_int,
addr: impl Into<SockaddrOutput<'a>>,
) -> Result<()> {
self.execute(syscall::Getsockname { sockfd, addr })?
}
#[inline]
fn getuid(&mut self) -> Result<uid_t> {
self.execute(syscall::Getuid)
}
#[inline]
fn ioctl(&mut self, fd: c_int, request: Ioctl, argp: Option<&mut [u8]>) -> Result<c_int> {
self.execute(syscall::Ioctl { fd, request, argp })?
}
#[inline]
fn listen(&mut self, sockfd: c_int, backlog: c_int) -> Result<()> {
self.execute(syscall::Listen { sockfd, backlog })?
}
fn madvise(
&mut self,
platform: &impl Platform,
addr: NonNull<c_void>,
length: c_size_t,
advice: c_int,
) -> Result<()>;
#[allow(clippy::too_many_arguments)]
fn mmap(
&mut self,
platform: &impl Platform,
addr: Option<NonNull<c_void>>,
length: c_size_t,
prot: c_int,
flags: c_int,
fd: c_int,
offset: off_t,
) -> Result<NonNull<c_void>>;
fn mprotect(
&mut self,
platform: &impl Platform,
addr: NonNull<c_void>,
len: c_size_t,
prot: c_int,
) -> Result<()>;
fn mremap(
&mut self,
platform: &impl Platform,
old_address: NonNull<c_void>,
old_size: c_size_t,
new_size: c_size_t,
flags: Option<MremapFlags>,
) -> Result<NonNull<c_void>> {
match flags {
None | Some(MremapFlags { FIXED: None, .. }) if new_size == old_size => Ok(old_address),
Some(MremapFlags {
FIXED: None,
DONTUNMAP: false,
}) if new_size < old_size => {
let source_slice =
platform.validate_slice::<u8>(old_address.as_ptr() as _, old_size)?;
let addr = &source_slice[new_size] as *const _;
let _ = self.munmap(
platform,
NonNull::new(addr as *mut c_void).ok_or(EINVAL)?,
old_size.checked_sub(new_size).ok_or(EINVAL)?,
);
Ok(old_address)
}
Some(MremapFlags {
FIXED: None,
DONTUNMAP,
}) if new_size > old_size => {
let source_slice =
platform.validate_slice::<u8>(old_address.as_ptr() as _, old_size)?;
let prot = PROT_WRITE | PROT_EXEC | PROT_READ;
let new_addr = self.mmap(
platform,
None,
new_size,
prot,
MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0,
)?;
let new_slice =
unsafe { slice::from_raw_parts_mut(new_addr.as_ptr() as *mut u8, new_size) };
new_slice[..old_size].copy_from_slice(source_slice);
if !DONTUNMAP {
let _ = self.munmap(platform, old_address, old_size);
}
Ok(NonNull::new(new_slice.as_ptr() as *mut _).unwrap())
}
_ => Err(ENOTSUP),
}
}
fn munmap(
&mut self,
platform: &impl Platform,
addr: NonNull<c_void>,
length: c_size_t,
) -> Result<()>;
#[inline]
fn nanosleep(&mut self, req: ×pec, rem: Option<&mut timespec>) -> Result<()> {
self.execute(syscall::Nanosleep { req, rem })?
}
fn open(&mut self, pathname: &[u8], flags: c_int, mode: Option<mode_t>) -> Result<c_int> {
self.execute(syscall::Open {
pathname,
flags,
mode,
})?
}
#[inline]
fn poll(&mut self, fds: &mut [pollfd], timeout: c_int) -> Result<c_int> {
self.execute(syscall::Poll { fds, timeout })?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn read(&mut self, fd: c_int, buf: &mut [u8]) -> Result<c_size_t> {
self.execute(syscall::Read { fd, buf })?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn readlink(&mut self, pathname: &[u8], buf: &mut [u8]) -> Result<c_size_t> {
self.execute(syscall::Readlink { pathname, buf })?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn readv<T: ?Sized, U, V>(&mut self, fd: c_int, iovs: &mut T) -> Result<c_size_t>
where
for<'a> &'a T: IntoIterator<Item = &'a U>,
for<'a> &'a mut T: IntoIterator<Item = &'a mut V>,
U: AsRef<[u8]>,
V: AsMut<[u8]>,
{
self.execute(syscall::Readv { fd, iovs })?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn recv(&mut self, sockfd: c_int, buf: &mut [u8], flags: c_int) -> Result<c_size_t> {
self.execute(syscall::Recv { sockfd, buf, flags })?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn recvfrom<'a>(
&mut self,
sockfd: c_int,
buf: &'a mut [u8],
flags: c_int,
src_addr: impl Into<SockaddrOutput<'a>>,
) -> Result<c_size_t> {
self.execute(syscall::Recvfrom {
sockfd,
buf,
flags,
src_addr,
})?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn rt_sigaction(
&mut self,
signum: c_int,
act: Option<&sigaction>,
oldact: Option<&mut Option<sigaction>>,
sigsetsize: c_size_t,
) -> Result<()> {
if signum >= SIGRTMAX || sigsetsize != 8 {
return Err(EINVAL);
}
let tls = self.thread_local_storage();
if let Some(oldact) = oldact {
*oldact = tls.actions[signum as usize];
}
if let Some(act) = act {
tls.actions[signum as usize] = Some(*act);
}
Ok(())
}
#[inline]
fn rt_sigprocmask(
&mut self,
how: c_int,
set: Option<&sigset_t>,
oldset: Option<&mut sigset_t>,
sigsetsize: c_size_t,
) -> Result<()> {
self.execute(syscall::RtSigprocmask {
how,
set,
oldset,
sigsetsize,
})?
}
#[inline]
fn send(&mut self, sockfd: c_int, buf: &[u8], flags: c_int) -> Result<c_size_t> {
self.execute(syscall::Send { sockfd, buf, flags })?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn sendto<'a>(
&mut self,
sockfd: c_int,
buf: &'a [u8],
flags: c_int,
dest_addr: impl Into<SockaddrInput<'a>>,
) -> Result<c_size_t> {
self.execute(syscall::Sendto {
sockfd,
buf,
flags,
dest_addr,
})?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn setsockopt<'a>(
&mut self,
sockfd: c_int,
level: c_int,
optname: c_int,
optval: Option<impl Into<SockoptInput<'a>>>,
) -> Result<c_int> {
self.execute(syscall::Setsockopt {
sockfd,
level,
optname,
optval,
})?
}
#[inline]
fn set_tid_address(&mut self, tidptr: &mut c_int) -> Result<pid_t> {
self.execute(syscall::SetTidAddress { tidptr })
}
#[inline]
fn sigaltstack(&mut self, ss: Option<&stack_t>, old_ss: Option<&mut stack_t>) -> Result<()> {
self.execute(syscall::Sigaltstack { ss, old_ss })?
}
#[inline]
fn socket(&mut self, domain: c_int, typ: c_int, protocol: c_int) -> Result<c_int> {
self.execute(syscall::Socket {
domain,
typ,
protocol,
})?
}
#[inline]
fn sync(&mut self) -> Result<()> {
self.execute(syscall::Sync)?
}
#[inline]
fn uname(&mut self, buf: &mut utsname) -> Result<()> {
self.execute(syscall::Uname { buf })?
}
#[inline]
fn write(&mut self, fd: c_int, buf: &[u8]) -> Result<c_size_t> {
self.execute(syscall::Write { fd, buf })?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn writev<T: ?Sized, U>(&mut self, fd: c_int, iovs: &T) -> Result<c_size_t>
where
for<'a> &'a T: IntoIterator<Item = &'a U>,
U: AsRef<[u8]>,
{
self.execute(syscall::Writev { fd, iovs })?
.unwrap_or_else(|| self.attacked())
}
#[inline]
unsafe fn syscall(
&mut self,
platform: &impl Platform,
registers: [usize; 7],
) -> Result<[usize; 2]> {
let [num, argv @ ..] = registers;
#[allow(non_upper_case_globals)]
match (num as _, argv) {
(SYS_accept, [sockfd, addr, addrlen, ..]) => {
let addr = if addr == 0 {
None
} else {
platform.validate_sockaddr_output(addr, addrlen).map(Some)?
};
self.accept(sockfd as _, addr).map(|ret| [ret as _, 0])
}
(SYS_accept4, [sockfd, addr, addrlen, flags, ..]) => {
let addr = if addr == 0 {
None
} else {
platform.validate_sockaddr_output(addr, addrlen).map(Some)?
};
self.accept4(sockfd as _, addr, flags as _)
.map(|ret| [ret as _, 0])
}
(SYS_arch_prctl, [code, addr, ..]) => self
.arch_prctl(platform, code as _, addr as _)
.map(|_| [0, 0]),
(SYS_bind, [sockfd, addr, addrlen, ..]) => {
let addr = platform.validate_slice(addr, addrlen)?;
self.bind(sockfd as _, addr).map(|_| [0, 0])
}
(SYS_brk, [addr, ..]) => self
.brk(platform, NonNull::new(addr as _))
.map(|ret| [ret.as_ptr() as _, 0]),
(SYS_clock_getres, [clockid, res, ..]) => {
let res = if res == 0 {
None
} else {
platform.validate_mut(res).map(Some)?
};
self.clock_getres(clockid as _, res).map(|_| [0, 0])
}
(SYS_clock_gettime, [clockid, tp, ..]) => {
let tp = platform.validate_mut(tp)?;
self.clock_gettime(clockid as _, tp).map(|_| [0, 0])
}
(SYS_close, [fd, ..]) => self.close(fd as _).map(|_| [0, 0]),
(SYS_connect, [sockfd, addr, addrlen, ..]) => {
let addr = platform.validate_slice(addr, addrlen)?;
self.connect(sockfd as _, addr).map(|_| [0, 0])
}
(SYS_dup, [oldfd, ..]) => self.dup(oldfd as _).map(|_| [0, 0]),
(SYS_dup2, [oldfd, newfd, ..]) => self.dup2(oldfd as _, newfd as _).map(|_| [0, 0]),
(SYS_dup3, [oldfd, newfd, flags, ..]) => self
.dup3(oldfd as _, newfd as _, flags as _)
.map(|_| [0, 0]),
(SYS_epoll_create1, [flags, ..]) => {
self.epoll_create1(flags as _).map(|ret| [ret as _, 0])
}
(SYS_epoll_ctl, [epfd, op, fd, event, ..]) => {
let event = platform.validate(event)?;
self.epoll_ctl(epfd as _, op as _, fd as _, event)
.map(|_| [0, 0])
}
(SYS_epoll_pwait, [epfd, events, maxevents, timeout, sigmask, ..]) => {
let events = platform.validate_slice_mut(events, maxevents)?;
if sigmask == 0 {
self.epoll_wait(epfd as _, events, timeout as _)
} else {
let sigmask = platform.validate(sigmask)?;
self.epoll_pwait(epfd as _, events, timeout as _, sigmask)
}
.map(|ret| [ret as _, 0])
}
(SYS_epoll_wait, [epfd, events, maxevents, timeout, ..]) => {
let events = platform.validate_slice_mut(events, maxevents)?;
self.epoll_wait(epfd as _, events, timeout as _)
.map(|ret| [ret as _, 0])
}
(SYS_eventfd2, [initval, flags, ..]) => self
.eventfd2(initval as _, flags as _)
.map(|ret| [ret as _, 0]),
(SYS_exit, [status, ..]) => self.exit(status as _).map(|_| self.attacked()),
(SYS_exit_group, [status, ..]) => self.exit_group(status as _).map(|_| self.attacked()),
(SYS_fcntl, [fd, cmd, arg, ..]) => self
.fcntl(fd as _, cmd as _, arg as _)
.map(|ret| [ret as _, 0]),
(SYS_fstat, [fd, statbuf, ..]) => {
let statbuf = platform.validate_mut(statbuf)?;
self.fstat(fd as _, statbuf).map(|_| [0, 0])
}
(SYS_getegid, ..) => self.getegid().map(|ret| [ret as _, 0]),
(SYS_geteuid, ..) => self.geteuid().map(|ret| [ret as _, 0]),
(SYS_getgid, ..) => self.getgid().map(|ret| [ret as _, 0]),
(SYS_getpid, ..) => self.getpid().map(|ret| [ret as _, 0]),
(SYS_getrandom, [buf, buflen, flags, ..]) => {
let buf = platform.validate_slice_mut(buf, buflen)?;
self.getrandom(buf, flags as _).map(|ret| [ret as _, 0])
}
(SYS_getsockname, [sockfd, addr, addrlen, ..]) => {
let addr = platform.validate_sockaddr_output(addr, addrlen)?;
self.getsockname(sockfd as _, addr).map(|_| [0, 0])
}
(SYS_getuid, ..) => self.getuid().map(|ret| [ret as _, 0]),
(SYS_ioctl, [fd, request, argp, ..]) => {
let argp = if argp == 0 {
None
} else {
match request as _ {
FIONBIO | FIONREAD => platform.validate_mut::<c_int>(argp).map(|argp| {
Some(slice::from_raw_parts_mut(
argp as *mut _ as _,
size_of::<c_int>(),
))
})?,
_ => return Err(ENOTSUP),
}
};
self.ioctl(fd as _, request as _, argp)
.map(|ret| [ret as _, 0])
}
(SYS_listen, [sockfd, backlog, ..]) => {
self.listen(sockfd as _, backlog as _).map(|_| [0, 0])
}
(SYS_madvise, [addr, length, advice, ..]) => {
let addr = NonNull::new(addr as _).ok_or(EFAULT)?;
self.madvise(platform, addr, length, advice as _)
.map(|_| [0, 0])
}
(SYS_mmap, [addr, length, prot, flags, fd, offset, ..]) => self
.mmap(
platform,
NonNull::new(addr as _),
length,
prot as _,
flags as _,
fd as _,
offset as _,
)
.map(|ret| [ret.as_ptr() as _, 0]),
(SYS_mprotect, [addr, len, prot, ..]) => {
let addr = NonNull::new(addr as _).ok_or(EFAULT)?;
self.mprotect(platform, addr, len, prot as _)
.map(|_| [0, 0])
}
(SYS_mremap, [old_address, old_size, new_size, flags, new_address, ..]) => {
let old_address = NonNull::new(old_address as _).ok_or(EFAULT)?;
let flags = match (flags as _, new_address) {
(0, 0) => None,
(MREMAP_MAYMOVE, 0) => Some(Default::default()),
(flags, 0) if flags == MREMAP_MAYMOVE | MREMAP_DONTUNMAP => Some(MremapFlags {
DONTUNMAP: true,
..Default::default()
}),
(flags, 0) if flags & MREMAP_FIXED != 0 => return Err(EINVAL),
(flags, new_address) if flags == MREMAP_MAYMOVE | MREMAP_FIXED => {
Some(MremapFlags {
FIXED: Some(NonNull::new(new_address as _).unwrap()),
..Default::default()
})
}
(flags, new_address)
if flags == MREMAP_MAYMOVE | MREMAP_FIXED | MREMAP_DONTUNMAP =>
{
Some(MremapFlags {
DONTUNMAP: true,
FIXED: Some(NonNull::new(new_address as _).unwrap()),
})
}
_ => return Err(EINVAL),
};
self.mremap(platform, old_address, old_size, new_size, flags)
.map(|ret| [ret.as_ptr() as _, 0])
}
(SYS_munmap, [addr, length, ..]) => {
let addr = NonNull::new(addr as _).ok_or(EFAULT)?;
self.munmap(platform, addr, length).map(|_| [0, 0])
}
(SYS_nanosleep, [req, rem, ..]) => {
let req = platform.validate(req)?;
let rem = if rem == 0 {
None
} else {
platform.validate_mut(rem).map(Some)?
};
self.nanosleep(req, rem).map(|_| [0, 0])
}
(SYS_open, [pathname, flags, mode, ..]) => {
let pathname = platform.validate_str(pathname)?;
let mode = if mode == 0 { None } else { Some(mode as _) };
self.open(pathname, flags as _, mode)
.map(|ret| [ret as _, 0])
}
(SYS_poll, [fds, nfds, timeout, ..]) => {
let fds = platform.validate_slice_mut(fds, nfds)?;
self.poll(fds, timeout as _).map(|ret| [ret as _, 0])
}
(SYS_read, [fd, buf, count, ..]) => {
let buf = platform.validate_slice_mut(buf, count)?;
self.read(fd as _, buf).map(|ret| [ret, 0])
}
(SYS_readlink, [pathname, buf, bufsiz, ..]) => {
let pathname = platform.validate_str(pathname)?;
let buf = platform.validate_slice_mut(buf, bufsiz)?;
self.readlink(pathname, buf).map(|ret| [ret, 0])
}
(SYS_readv, [fd, iov, iovcnt, ..]) => {
let iovs = platform.validate_iovec_slice_mut(iov, iovcnt)?;
self.readv(fd as _, iovs).map(|ret| [ret, 0])
}
(SYS_recvfrom, [sockfd, buf, len, flags, src_addr, addrlen, ..]) => {
let buf = platform.validate_slice_mut(buf, len)?;
if src_addr == 0 {
self.recv(sockfd as _, buf, flags as _)
} else {
let src_addr = platform.validate_sockaddr_output(src_addr, addrlen)?;
self.recvfrom(sockfd as _, buf, flags as _, src_addr)
}
.map(|ret| [ret, 0])
}
(SYS_rt_sigaction, [signum, act, oldact, sigsetsize, ..]) => {
let act = if act == 0 {
None
} else {
platform.validate(act).map(Some)?
};
if oldact == 0 {
self.rt_sigaction(signum as _, act, None, sigsetsize as _)?
} else {
let sys_oldact = platform.validate_mut(oldact)?;
let mut oldact = None;
self.rt_sigaction(signum as _, act, Some(&mut oldact), sigsetsize as _)?;
if let Some(oldact) = oldact {
*sys_oldact = oldact;
}
}
Ok([0, 0])
}
(SYS_rt_sigprocmask, [how, set, oldset, sigsetsize, ..]) => {
let set = if set == 0 {
None
} else {
platform.validate(set).map(Some)?
};
let oldset = if oldset == 0 {
None
} else {
platform.validate_mut(oldset).map(Some)?
};
self.rt_sigprocmask(how as _, set, oldset, sigsetsize as _)
.map(|_| [0, 0])
}
(SYS_sendto, [sockfd, buf, len, flags, dest_addr, addrlen]) => {
let buf = platform.validate_slice(buf, len)?;
if dest_addr == 0 {
self.send(sockfd as _, buf, flags as _)
} else {
let dest_addr = platform.validate_slice(dest_addr, addrlen)?;
self.sendto(sockfd as _, buf, flags as _, dest_addr)
}
.map(|ret| [ret, 0])
}
(SYS_setsockopt, [sockfd, level, optname, optval, optlen, ..]) => {
let optval = if optval == 0 {
None
} else {
platform.validate_slice::<u8>(optval, optlen).map(Some)?
};
self.setsockopt(sockfd as _, level as _, optname as _, optval)
.map(|ret| [ret as _, 0])
}
(SYS_set_tid_address, [tidptr, ..]) => {
let tidptr = platform.validate_mut(tidptr)?;
self.set_tid_address(tidptr).map(|ret| [ret as _, 0])
}
(SYS_sigaltstack, [ss, old_ss, ..]) => {
let ss = if ss == 0 {
None
} else {
platform.validate(ss).map(Some)?
};
let old_ss = if old_ss == 0 {
None
} else {
platform.validate_mut(old_ss).map(Some)?
};
self.sigaltstack(ss, old_ss).map(|_| [0, 0])
}
(SYS_socket, [domain, typ, protocol, ..]) => self
.socket(domain as _, typ as _, protocol as _)
.map(|ret| [ret as _, 0]),
(SYS_sync, ..) => self.sync().map(|_| [0, 0]),
(SYS_uname, [buf, ..]) => {
let buf = platform.validate_mut(buf)?;
self.uname(buf).map(|_| [0, 0])
}
(SYS_write, [fd, buf, count, ..]) => {
let buf = platform.validate_slice(buf, count)?;
self.write(fd as _, buf).map(|ret| [ret, 0])
}
(SYS_writev, [fd, iov, iovcnt, ..]) => {
let iovs = platform.validate_iovec_slice(iov, iovcnt)?;
self.writev(fd as _, iovs).map(|ret| [ret, 0])
}
_ => Err(ENOSYS),
}
}
#[cfg_attr(feature = "doc", doc = "Executes [gdbstub::conn::Connection::flush]")]
#[inline]
fn gdb_flush(&mut self) -> Result<()> {
self.execute(gdbcall::Flush)?
}
#[cfg_attr(
feature = "doc",
doc = "Executes [gdbstub::conn::Connection::on_session_start]"
)]
#[inline]
fn gdb_on_session_start(&mut self) -> Result<()> {
self.execute(gdbcall::OnSessionStart)?
}
#[cfg_attr(feature = "doc", doc = "Executes [gdbstub::conn::ConnectionExt::peek]")]
#[inline]
fn gdb_peek(&mut self) -> Result<Option<u8>> {
self.execute(gdbcall::Peek)?
}
#[cfg_attr(feature = "doc", doc = "Executes [gdbstub::conn::ConnectionExt::read]")]
#[inline]
fn gdb_read(&mut self) -> Result<u8> {
self.execute(gdbcall::Read)?
}
#[cfg_attr(feature = "doc", doc = "Executes [gdbstub::conn::Connection::write]")]
#[inline]
fn gdb_write(&mut self, byte: u8) -> Result<()> {
self.execute(gdbcall::Write { byte })?
}
#[cfg_attr(
feature = "doc",
doc = "Executes [gdbstub::conn::Connection::write_all] and returns the amount of bytes written"
)]
#[inline]
fn gdb_write_all(&mut self, buf: &[u8]) -> Result<usize> {
self.execute(gdbcall::WriteAll { buf })?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn balloon_memory(
&mut self,
size_exponent: usize,
pages: usize,
addr: *mut c_void,
) -> Result<usize> {
self.execute(enarxcall::BalloonMemory {
size_exponent,
pages,
addr,
})?
}
#[inline]
fn cpuid(&mut self, leaf: u32, sub_leaf: u32, result: &mut CpuidResult) -> Result<()> {
self.execute(enarxcall::Cpuid {
leaf,
sub_leaf,
result,
})?
}
#[inline]
fn get_sgx_quote(&mut self, report: &sgx::Report, quote: &mut [u8]) -> Result<usize> {
self.execute(enarxcall::GetSgxQuote { report, quote })?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn get_sgx_quote_size(&mut self) -> Result<usize> {
self.execute(enarxcall::GetSgxQuoteSize)?
}
#[inline]
fn get_sgx_target_info(&mut self, info: &mut sgx::TargetInfo) -> Result<()> {
self.execute(enarxcall::GetSgxTargetInfo { info })?
}
#[inline]
fn get_snp_vcek(&mut self, vcek: &mut [u8]) -> Result<usize> {
self.execute(enarxcall::GetSnpVcek { vcek })?
.unwrap_or_else(|| self.attacked())
}
#[inline]
fn mem_info(&mut self) -> Result<usize> {
self.execute(enarxcall::MemInfo)?
}
#[inline]
fn mmap_host(&mut self, addr: NonNull<c_void>, length: usize, prot: c_int) -> Result<()> {
self.execute(enarxcall::MmapHost { addr, length, prot })?
}
#[inline]
fn mprotect_host(&mut self, addr: NonNull<c_void>, length: usize, prot: c_int) -> Result<()> {
self.execute(enarxcall::MprotectHost { addr, length, prot })?
}
#[inline]
fn munmap_host(&mut self, addr: NonNull<c_void>, length: usize) -> Result<()> {
self.execute(enarxcall::MunmapHost { addr, length })?
}
#[inline]
fn trim_sgx_pages(&mut self, addr: NonNull<c_void>, length: usize) -> Result<()> {
self.execute(enarxcall::TrimSgxPages { addr, length })?
}
}