use super::BaseSyscallHandler;
use crate::untrusted::{AddressValidator, UntrustedRef, UntrustedRefMut, Validate, ValidateSlice};
use crate::{request, Block, Result};
pub trait NetworkSyscallHandler: BaseSyscallHandler + AddressValidator + Sized {
fn socket(&mut self, domain: libc::c_int, type_: libc::c_int, protocol: libc::c_int) -> Result {
self.trace("socket", 3);
unsafe { self.proxy(request!(libc::SYS_socket => domain, type_, protocol)) }
}
fn bind(&mut self, fd: libc::c_int, addr: UntrustedRef<u8>, addrlen: libc::size_t) -> Result {
self.trace("bind", 3);
if addrlen > Block::buf_capacity() {
return Err(libc::EINVAL);
}
let addr = addr.validate_slice(addrlen, self).ok_or(libc::EFAULT)?;
let c = self.new_cursor();
let (_, addr) = c.copy_from_slice(addr.as_ref()).or(Err(libc::EMSGSIZE))?;
let addr = addr.as_ptr();
let host_virt = Self::translate_shim_to_host_addr(addr);
unsafe { self.proxy(request!(libc::SYS_bind => fd, host_virt, addrlen)) }
}
fn listen(&mut self, sockfd: libc::c_int, backlog: libc::c_int) -> Result {
self.trace("listen", 2);
unsafe { self.proxy(request!(libc::SYS_listen => sockfd, backlog)) }
}
fn getsockname(
&mut self,
fd: libc::c_int,
addr: UntrustedRefMut<u8>,
addrlen: UntrustedRefMut<libc::socklen_t>,
) -> Result {
self.trace("getsockname", 3);
let addrlen = addrlen.validate(self).ok_or(libc::EFAULT)?;
let c = self.new_cursor();
let (c, block_addr) = c.alloc::<u8>(*addrlen as _).or(Err(libc::EMSGSIZE))?;
let (_, block_addrlen) = c.write(addrlen).or(Err(libc::EINVAL))?;
let block_addr_ptr = block_addr[0].as_ptr();
let block_addr = Self::translate_shim_to_host_addr(block_addr_ptr);
let block_addrlen = Self::translate_shim_to_host_addr(block_addrlen as _);
let ret = unsafe {
self.proxy(request!(libc::SYS_getsockname => fd, block_addr, block_addrlen))
}?;
unsafe {
let c = self.new_cursor();
let (c, _) = c.alloc::<u8>(*addrlen as _).or(Err(libc::EMSGSIZE))?;
let (_, block_addrlen) = c.read::<libc::socklen_t>().or(Err(libc::EMSGSIZE))?;
let addr = addr.validate_slice(*addrlen, self).ok_or(libc::EFAULT)?;
let len = (*addrlen).min(block_addrlen) as usize;
let c = self.new_cursor();
c.copy_into_slice(*addrlen as _, &mut addr[..len])
.or(Err(libc::EMSGSIZE))?;
*addrlen = block_addrlen;
}
Ok(ret)
}
fn accept(
&mut self,
fd: libc::c_int,
addr: UntrustedRefMut<u8>,
addrlen: UntrustedRefMut<libc::socklen_t>,
) -> Result {
self.accept4(fd, addr, addrlen, 0)
}
fn accept4(
&mut self,
fd: libc::c_int,
addr: UntrustedRefMut<u8>,
addrlen: UntrustedRefMut<libc::socklen_t>,
flags: libc::c_int,
) -> Result {
self.trace("accept4", 4);
if addr.as_ptr().is_null() {
return unsafe {
self.proxy(
request!(libc::SYS_accept4 => fd, addr.as_ptr(), addrlen.as_ptr(), flags),
)
};
}
let addrlen = addrlen.validate(self).ok_or(libc::EFAULT)?;
let c = self.new_cursor();
let (c, block_addr) = c.alloc::<u8>(*addrlen as _).or(Err(libc::EMSGSIZE))?;
let (_, block_addrlen) = c.write(addrlen).or(Err(libc::EINVAL))?;
let block_addr_ptr = block_addr[0].as_ptr();
let block_addr = Self::translate_shim_to_host_addr(block_addr_ptr);
let block_addrlen = Self::translate_shim_to_host_addr(block_addrlen as _);
let ret = unsafe {
self.proxy(request!(libc::SYS_accept4 => fd, block_addr, block_addrlen, flags))
}?;
unsafe {
let c = self.new_cursor();
let (c, _) = c.alloc::<u8>(*addrlen as _).or(Err(libc::EMSGSIZE))?;
let (_, block_addrlen) = c.read::<libc::socklen_t>().or(Err(libc::EMSGSIZE))?;
let addr = addr.validate_slice(*addrlen, self).ok_or(libc::EFAULT)?;
let len = (*addrlen).min(block_addrlen) as usize;
let c = self.new_cursor();
c.copy_into_slice(*addrlen as _, &mut addr[..len])
.or(Err(libc::EMSGSIZE))?;
*addrlen = block_addrlen;
}
Ok(ret)
}
fn connect(
&mut self,
fd: libc::c_int,
addr: UntrustedRef<u8>,
addrlen: libc::size_t,
) -> Result {
self.trace("connect", 3);
if addrlen > Block::buf_capacity() {
return Err(libc::EINVAL);
}
let addr = addr.validate_slice(addrlen, self).ok_or(libc::EFAULT)?;
let c = self.new_cursor();
let (_, addr) = c.copy_from_slice(addr.as_ref()).or(Err(libc::EMSGSIZE))?;
let addr = addr.as_ptr();
let host_virt = Self::translate_shim_to_host_addr(addr);
unsafe { self.proxy(request!(libc::SYS_connect => fd, host_virt, addrlen)) }
}
fn recvfrom(
&mut self,
fd: libc::c_int,
buf: UntrustedRefMut<u8>,
count: libc::size_t,
flags: libc::c_int,
src_addr: UntrustedRefMut<u8>,
addrlen: UntrustedRefMut<libc::socklen_t>,
) -> Result {
self.trace("recvfrom", 6);
let count = usize::min(count, Block::buf_capacity());
let addrlen = addrlen.validate(self);
let len = match addrlen {
None => 0,
Some(ref e) => **e,
};
if (count + (len as usize)) > Block::buf_capacity() {
return Err(libc::EINVAL);
}
let buf = buf.validate_slice(count, self).ok_or(libc::EFAULT)?;
let c = self.new_cursor();
let (c, hostbuf) = c.alloc::<u8>(count).or(Err(libc::EMSGSIZE))?;
let hostbuf = hostbuf.as_ptr();
let host_buf_virt = Self::translate_shim_to_host_addr(hostbuf);
let (host_addr, block_addrlen) = if src_addr.as_ptr().is_null() {
(src_addr.as_ptr() as usize, 0)
} else {
let (c, block_addr) = c.alloc::<u8>(len as _).or(Err(libc::EMSGSIZE))?;
let block_addr_ptr = block_addr[0].as_ptr();
let block_addr = Self::translate_shim_to_host_addr(block_addr_ptr);
let (_c, block_addrlen) = c.write(addrlen.as_deref().unwrap()).or(Err(libc::EINVAL))?;
let block_addrlen = Self::translate_shim_to_host_addr(block_addrlen as _);
(block_addr, block_addrlen)
};
let ret = unsafe {
self.proxy(
request!(libc::SYS_recvfrom => fd, host_buf_virt, count, flags, host_addr, block_addrlen),
)?
};
let result_len: usize = ret[0].into();
if count < result_len {
self.attacked();
}
if src_addr.as_ptr().is_null() {
let c = self.new_cursor();
unsafe {
c.copy_into_slice(count, buf[..result_len].as_mut())
.or(Err(libc::EFAULT))?
};
} else {
let addrlen = addrlen.unwrap();
let addr = src_addr
.validate_slice(*addrlen as usize, self)
.ok_or(libc::EFAULT)?;
let c = self.new_cursor();
let c = unsafe {
c.copy_into_slice(count, buf[..result_len].as_mut())
.or(Err(libc::EFAULT))?
};
unsafe {
let (c, addr_buf) = c.alloc::<u8>(*addrlen as _).or(Err(libc::EMSGSIZE))?;
let (_, block_addrlen) = c.read::<libc::socklen_t>().or(Err(libc::EMSGSIZE))?;
let len = (*addrlen).min(block_addrlen) as usize;
addr_buf.as_ptr().copy_to(addr.as_mut_ptr() as _, len);
*addrlen = block_addrlen;
}
}
Ok(ret)
}
fn sendto(
&mut self,
sockfd: libc::c_int,
buf: UntrustedRef<u8>,
count: libc::size_t,
flags: libc::c_int,
dest_addr: UntrustedRef<u8>,
addrlen: libc::size_t,
) -> Result {
self.trace("sendto", 6);
let count = usize::min(count, Block::buf_capacity());
let buf = buf.validate_slice(count, self).ok_or(libc::EFAULT)?;
let dest_addr = if dest_addr.as_ptr().is_null() {
None
} else {
Some(
dest_addr
.validate_slice(addrlen, self)
.ok_or(libc::EFAULT)?,
)
};
let c = self.new_cursor();
let (c, buf) = c.copy_from_slice(buf.as_ref()).or(Err(libc::EMSGSIZE))?;
let buf = buf.as_ptr();
let buf_host_virt = Self::translate_shim_to_host_addr(buf);
let addr_host_virt = if let Some(dest_addr) = dest_addr {
let (_, dest_addr) = c
.copy_from_slice(dest_addr.as_ref())
.or(Err(libc::EMSGSIZE))?;
let dest_addr = dest_addr.as_ptr();
Self::translate_shim_to_host_addr(dest_addr)
} else {
0
};
let ret = unsafe {
self.proxy(request!(libc::SYS_sendto => sockfd, buf_host_virt, count, flags, addr_host_virt, addrlen))?
};
let result_len: usize = ret[0].into();
if result_len > count {
self.attacked()
}
Ok(ret)
}
fn setsockopt(
&mut self,
sockfd: libc::c_int,
level: libc::c_int,
optname: libc::c_int,
optval: UntrustedRef<u8>,
optlen: libc::socklen_t,
) -> Result {
self.trace("setsockopt", 5);
let optval = optval.validate_slice(optlen, self).ok_or(libc::EFAULT)?;
let c = self.new_cursor();
let (_, buf) = c.copy_from_slice(optval).or(Err(libc::EMSGSIZE))?;
let host_virt = Self::translate_shim_to_host_addr(buf.as_ptr());
unsafe {
self.proxy(request!(libc::SYS_setsockopt => sockfd, level,optname, host_virt, optlen))
}
}
}