SGX target: implement networking

This commit is contained in:
Jethro Beekman 2018-09-19 15:59:06 -07:00
parent 1a894f135e
commit 59b79f71e9
2 changed files with 167 additions and 53 deletions

View File

@ -55,6 +55,61 @@ pub fn close(fd: Fd) {
unsafe { raw::close(fd) }
}
fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
String::from_utf8(copy_user_buffer(buf))
.unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
}
pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> {
unsafe {
let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
let mut local = alloc::User::<ByteBuffer>::uninitialized();
let fd = raw::bind_stream(
addr_user.as_ptr(),
addr_user.len(),
local.as_raw_mut_ptr()
).from_sgx_result()?;
let local = string_from_bytebuffer(&local, "bind_stream", "local_addr");
Ok((fd, local))
}
}
pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> {
unsafe {
let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
// without forcing coercion?
let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
let fd = raw::accept_stream(
fd,
local.as_raw_mut_ptr(),
peer.as_raw_mut_ptr()
).from_sgx_result()?;
let local = string_from_bytebuffer(&local, "accept_stream", "local_addr");
let peer = string_from_bytebuffer(&peer, "accept_stream", "peer_addr");
Ok((fd, local, peer))
}
}
pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> {
unsafe {
let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
// without forcing coercion?
let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
let fd = raw::connect_stream(
addr_user.as_ptr(),
addr_user.len(),
local.as_raw_mut_ptr(),
peer.as_raw_mut_ptr()
).from_sgx_result()?;
let local = string_from_bytebuffer(&local, "connect_stream", "local_addr");
let peer = string_from_bytebuffer(&peer, "connect_stream", "peer_addr");
Ok((fd, local, peer))
}
}
pub fn launch_thread() -> IoResult<()> {
unsafe { raw::launch_thread().from_sgx_result() }
}

View File

@ -10,144 +10,182 @@
use fmt;
use io;
use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
use time::Duration;
use sys::{unsupported, Void};
use sys::{unsupported, Void, sgx_ineffective};
use sys::fd::FileDesc;
use convert::TryFrom;
use error;
use sync::Arc;
pub struct TcpStream(Void);
use super::abi::usercalls;
const DEFAULT_FAKE_TTL: u32 = 64;
#[derive(Debug, Clone)]
struct Socket {
inner: Arc<FileDesc>,
local_addr: String,
}
impl Socket {
fn new(fd: usercalls::Fd, local_addr: String) -> Socket {
Socket { inner: Arc::new(FileDesc::new(fd)), local_addr }
}
}
#[derive(Debug, Clone)]
pub struct TcpStream {
inner: Socket,
peer_addr: String,
}
fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> {
match result {
Ok(saddr) => Ok(saddr.to_string()),
// need to downcast twice because io::Error::into_inner doesn't return the original
// value if the conversion fails
Err(e) => if e.get_ref().and_then(|e| e.downcast_ref::<NonIpSockAddr>()).is_some() {
Ok(e.into_inner().unwrap().downcast::<NonIpSockAddr>().unwrap().host)
} else {
Err(e)
}
}
}
fn addr_to_sockaddr(addr: &str) -> io::Result<SocketAddr> {
// unwrap OK: if an iterator is returned, we're guaranteed to get exactly one entry
addr.to_socket_addrs().map(|mut it| it.next().unwrap())
}
impl TcpStream {
pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
unsupported()
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
let addr = io_err_to_addr(addr)?;
let (fd, local_addr, peer_addr) = usercalls::connect_stream(&addr)?;
Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr })
}
pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
unsupported()
pub fn connect_timeout(addr: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
Self::connect(Ok(addr)) // FIXME: ignoring timeout
}
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
match self.0 {}
sgx_ineffective(())
}
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
match self.0 {}
sgx_ineffective(())
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
match self.0 {}
sgx_ineffective(None)
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
match self.0 {}
sgx_ineffective(None)
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
match self.0 {}
Ok(0)
}
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
match self.0 {}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.inner.read(buf)
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
match self.0 {}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.inner.inner.write(buf)
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
addr_to_sockaddr(&self.peer_addr)
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
addr_to_sockaddr(&self.inner.local_addr)
}
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
match self.0 {}
sgx_ineffective(())
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
match self.0 {}
Ok(self.clone())
}
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
match self.0 {}
sgx_ineffective(())
}
pub fn nodelay(&self) -> io::Result<bool> {
match self.0 {}
sgx_ineffective(false)
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
match self.0 {}
sgx_ineffective(())
}
pub fn ttl(&self) -> io::Result<u32> {
match self.0 {}
sgx_ineffective(DEFAULT_FAKE_TTL)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
match self.0 {}
Ok(None)
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
match self.0 {}
sgx_ineffective(())
}
}
impl fmt::Debug for TcpStream {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {}
}
#[derive(Debug, Clone)]
pub struct TcpListener {
inner: Socket,
}
pub struct TcpListener(Void);
impl TcpListener {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
unsupported()
pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
let addr = io_err_to_addr(addr)?;
let (fd, local_addr) = usercalls::bind_stream(&addr)?;
Ok(TcpListener { inner: Socket::new(fd, local_addr) })
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
addr_to_sockaddr(&self.inner.local_addr)
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
match self.0 {}
let (fd, local_addr, peer_addr) = usercalls::accept_stream(self.inner.inner.raw())?;
let ret_peer = addr_to_sockaddr(&peer_addr).unwrap_or_else(|_| ([0; 4], 0).into());
Ok((TcpStream { inner: Socket::new(fd, local_addr), peer_addr }, ret_peer))
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
match self.0 {}
Ok(self.clone())
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
match self.0 {}
sgx_ineffective(())
}
pub fn ttl(&self) -> io::Result<u32> {
match self.0 {}
sgx_ineffective(DEFAULT_FAKE_TTL)
}
pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
match self.0 {}
sgx_ineffective(())
}
pub fn only_v6(&self) -> io::Result<bool> {
match self.0 {}
sgx_ineffective(false)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
match self.0 {}
Ok(None)
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
}
impl fmt::Debug for TcpListener {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {}
sgx_ineffective(())
}
}
@ -285,9 +323,30 @@ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
}
}
#[derive(Debug)]
pub struct NonIpSockAddr {
host: String
}
impl error::Error for NonIpSockAddr {
fn description(&self) -> &str {
"Failed to convert address to SocketAddr"
}
}
impl fmt::Display for NonIpSockAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Failed to convert address to SocketAddr: {}", self.host)
}
}
pub struct LookupHost(Void);
impl LookupHost {
fn new(host: String) -> io::Result<LookupHost> {
Err(io::Error::new(io::ErrorKind::Other, NonIpSockAddr { host }))
}
pub fn port(&self) -> u16 {
match self.0 {}
}
@ -303,16 +362,16 @@ fn next(&mut self) -> Option<SocketAddr> {
impl<'a> TryFrom<&'a str> for LookupHost {
type Error = io::Error;
fn try_from(_v: &'a str) -> io::Result<LookupHost> {
unsupported()
fn try_from(v: &'a str) -> io::Result<LookupHost> {
LookupHost::new(v.to_owned())
}
}
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
type Error = io::Error;
fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
unsupported()
fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
LookupHost::new(format!("{}:{}", host, port))
}
}