From 505167d7c58f68170118f96436c85e0587e6d3f5 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 25 Dec 2018 13:10:16 +0530 Subject: [PATCH 1/2] Fix build on latest git master --- src/libstd/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index af5d511c035ee..63489aeb374eb 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -314,7 +314,8 @@ #![feature(alloc_layout_extra)] #![feature(maybe_uninit)] #![cfg_attr(target_env = "sgx", feature(global_asm, range_contains, slice_index_methods, - decl_macro, coerce_unsized, sgx_platform))] + decl_macro, coerce_unsized, sgx_platform, + min_const_unsafe_fn))] #![default_lib_allocator] From be565615dbed87a0d3fcdb7f62b2080b3dc288fa Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 25 Dec 2018 13:11:04 +0530 Subject: [PATCH 2/2] Add `io` and `arch` modules to `std::os::fortanix_sgx` --- src/libstd/os/fortanix_sgx/mod.rs | 2 + src/libstd/sys/sgx/ext/arch.rs | 84 +++++++++++++++++++++ src/libstd/sys/sgx/ext/io.rs | 119 ++++++++++++++++++++++++++++++ src/libstd/sys/sgx/ext/mod.rs | 14 ++++ src/libstd/sys/sgx/fd.rs | 16 +++- src/libstd/sys/sgx/mod.rs | 7 ++ src/libstd/sys/sgx/net.rs | 73 +++++++++++++++--- 7 files changed, 305 insertions(+), 10 deletions(-) create mode 100644 src/libstd/sys/sgx/ext/arch.rs create mode 100644 src/libstd/sys/sgx/ext/io.rs create mode 100644 src/libstd/sys/sgx/ext/mod.rs diff --git a/src/libstd/os/fortanix_sgx/mod.rs b/src/libstd/os/fortanix_sgx/mod.rs index 825e7f359d64c..0f32602043411 100644 --- a/src/libstd/os/fortanix_sgx/mod.rs +++ b/src/libstd/os/fortanix_sgx/mod.rs @@ -65,3 +65,5 @@ pub mod usercalls { pub mod mem { pub use sys::abi::mem::*; } + +pub use sys::ext::{io, arch}; diff --git a/src/libstd/sys/sgx/ext/arch.rs b/src/libstd/sys/sgx/ext/arch.rs new file mode 100644 index 0000000000000..377210f5d699c --- /dev/null +++ b/src/libstd/sys/sgx/ext/arch.rs @@ -0,0 +1,84 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! SGX-specific access to architectural features. +//! +//! The functionality in this module is further documented in the Intel +//! Software Developer's Manual, Volume 3, Chapter 40. +#![unstable(feature = "sgx_platform", issue = "56975")] + +use mem::MaybeUninit; + +/// Wrapper struct to force 16-byte alignment. +#[repr(align(16))] +#[unstable(feature = "sgx_platform", issue = "56975")] +pub struct Align16(pub T); + +/// Wrapper struct to force 128-byte alignment. +#[repr(align(128))] +#[unstable(feature = "sgx_platform", issue = "56975")] +pub struct Align128(pub T); + +/// Wrapper struct to force 512-byte alignment. +#[repr(align(512))] +#[unstable(feature = "sgx_platform", issue = "56975")] +pub struct Align512(pub T); + +const ENCLU_EREPORT: u32 = 0; +const ENCLU_EGETKEY: u32 = 1; + +/// Call the `EGETKEY` instruction to obtain a 128-bit secret key. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub fn egetkey(request: &Align512<[u8; 512]>) -> Result, u32> { + unsafe { + let mut out = MaybeUninit::uninitialized(); + let error; + + asm!( + "enclu" + : "={eax}"(error) + : "{eax}"(ENCLU_EGETKEY), + "{rbx}"(request), + "{rcx}"(out.get_mut()) + : "flags" + ); + + match error { + 0 => Ok(out.into_inner()), + err => Err(err), + } + } +} + +/// Call the `EREPORT` instruction. +/// +/// This creates a cryptographic report describing the contents of the current +/// enclave. The report may be verified by the enclave described in +/// `targetinfo`. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub fn ereport( + targetinfo: &Align512<[u8; 512]>, + reportdata: &Align128<[u8; 64]>, +) -> Align512<[u8; 432]> { + unsafe { + let mut report = MaybeUninit::uninitialized(); + + asm!( + "enclu" + : /* no output registers */ + : "{eax}"(ENCLU_EREPORT), + "{rbx}"(targetinfo), + "{rcx}"(reportdata), + "{rdx}"(report.get_mut()) + ); + + report.into_inner() + } +} diff --git a/src/libstd/sys/sgx/ext/io.rs b/src/libstd/sys/sgx/ext/io.rs new file mode 100644 index 0000000000000..55cc4c9ba1ffb --- /dev/null +++ b/src/libstd/sys/sgx/ext/io.rs @@ -0,0 +1,119 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! SGX-specific extensions to general I/O primitives +//! +//! SGX file descriptors behave differently from Unix file descriptors. See the +//! description of [`TryIntoRawFd`](trait.TryIntoRawFd.html) for more details. +#![unstable(feature = "sgx_platform", issue = "56975")] + +pub use sys::abi::usercalls::raw::Fd as RawFd; +use net; +use sys::{self, AsInner, FromInner, IntoInner, TryIntoInner}; + +/// A trait to extract the raw SGX file descriptor from an underlying +/// object. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub trait AsRawFd { + /// Extracts the raw file descriptor. + /// + /// This method does **not** pass ownership of the raw file descriptor + /// to the caller. The descriptor is only guaranteed to be valid while + /// the original object has not yet been destroyed. + #[unstable(feature = "sgx_platform", issue = "56975")] + fn as_raw_fd(&self) -> RawFd; +} + +/// A trait to express the ability to construct an object from a raw file +/// descriptor. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub trait FromRawFd { + /// Constructs a new instance of `Self` from the given raw file + /// descriptor. + /// + /// This function **consumes ownership** of the specified file + /// descriptor. The returned object will take responsibility for closing + /// it when the object goes out of scope. + /// + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + #[unstable(feature = "sgx_platform", issue = "56975")] + unsafe fn from_raw_fd(fd: RawFd) -> Self; +} + +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw file descriptor. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub trait TryIntoRawFd: Sized { + /// Consumes this object, returning the raw underlying file descriptor, if + /// this object is not cloned. + /// + /// This function **transfers ownership** of the underlying file descriptor + /// to the caller. Callers are then the unique owners of the file descriptor + /// and must close the descriptor once it's no longer needed. + /// + /// Unlike other platforms, on SGX, the file descriptor is shared between + /// all clones of an object. To avoid race conditions, this function will + /// only return `Ok` when called on the final clone. + #[unstable(feature = "sgx_platform", issue = "56975")] + fn try_into_raw_fd(self) -> Result; +} + +impl AsRawFd for net::TcpStream { + fn as_raw_fd(&self) -> RawFd { *self.as_inner().as_inner().as_inner().as_inner() } +} + +impl AsRawFd for net::TcpListener { + fn as_raw_fd(&self) -> RawFd { *self.as_inner().as_inner().as_inner().as_inner() } +} + +impl FromRawFd for net::TcpStream { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { + let fd = sys::fd::FileDesc::from_inner(fd); + let socket = sys::net::Socket::from_inner(fd); + net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, None))) + } +} + +impl FromRawFd for net::TcpListener { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { + let fd = sys::fd::FileDesc::from_inner(fd); + let socket = sys::net::Socket::from_inner(fd); + net::TcpListener::from_inner(sys::net::TcpListener::from_inner(socket)) + } +} + +impl TryIntoRawFd for net::TcpStream { + fn try_into_raw_fd(self) -> Result { + let (socket, peer_addr) = self.into_inner().into_inner(); + match socket.try_into_inner() { + Ok(fd) => Ok(fd.into_inner()), + Err(socket) => { + let sys = sys::net::TcpStream::from_inner((socket, peer_addr)); + Err(net::TcpStream::from_inner(sys)) + } + } + } +} + +impl TryIntoRawFd for net::TcpListener { + fn try_into_raw_fd(self) -> Result { + match self.into_inner().into_inner().try_into_inner() { + Ok(fd) => Ok(fd.into_inner()), + Err(socket) => { + let sys = sys::net::TcpListener::from_inner(socket); + Err(net::TcpListener::from_inner(sys)) + } + } + } +} diff --git a/src/libstd/sys/sgx/ext/mod.rs b/src/libstd/sys/sgx/ext/mod.rs new file mode 100644 index 0000000000000..8e505a23c422d --- /dev/null +++ b/src/libstd/sys/sgx/ext/mod.rs @@ -0,0 +1,14 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "sgx_platform", issue = "56975")] + +pub mod arch; +pub mod io; diff --git a/src/libstd/sys/sgx/fd.rs b/src/libstd/sys/sgx/fd.rs index 31c4199c6cda1..1f7024b2c462e 100644 --- a/src/libstd/sys/sgx/fd.rs +++ b/src/libstd/sys/sgx/fd.rs @@ -12,7 +12,7 @@ use fortanix_sgx_abi::Fd; use io; use mem; -use sys_common::AsInner; +use sys::{AsInner, FromInner, IntoInner}; use super::abi::usercalls; #[derive(Debug)] @@ -51,6 +51,20 @@ impl AsInner for FileDesc { fn as_inner(&self) -> &Fd { &self.fd } } +impl IntoInner for FileDesc { + fn into_inner(self) -> Fd { + let fd = self.fd; + mem::forget(self); + fd + } +} + +impl FromInner for FileDesc { + fn from_inner(fd: Fd) -> FileDesc { + FileDesc { fd } + } +} + impl Drop for FileDesc { fn drop(&mut self) { usercalls::close(self.fd) diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index dd6862e908e06..f2b569e17660d 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -27,6 +27,7 @@ pub mod backtrace; pub mod cmath; pub mod condvar; pub mod env; +pub mod ext; pub mod fd; pub mod fs; pub mod memchr; @@ -151,3 +152,9 @@ pub fn hashmap_random_keys() -> (u64, u64) { } (rdrand64(), rdrand64()) } + +pub use sys_common::{AsInner, FromInner, IntoInner}; + +pub trait TryIntoInner: Sized { + fn try_into_inner(self) -> Result; +} diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs index 9cfe821fe5154..bb33a8aca79ae 100644 --- a/src/libstd/sys/sgx/net.rs +++ b/src/libstd/sys/sgx/net.rs @@ -12,7 +12,7 @@ use fmt; use io; use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr, ToSocketAddrs}; use time::Duration; -use sys::{unsupported, Void, sgx_ineffective}; +use sys::{unsupported, Void, sgx_ineffective, AsInner, FromInner, IntoInner, TryIntoInner}; use sys::fd::FileDesc; use convert::TryFrom; use error; @@ -23,21 +23,38 @@ use super::abi::usercalls; const DEFAULT_FAKE_TTL: u32 = 64; #[derive(Debug, Clone)] -struct Socket { +pub struct Socket { inner: Arc, - local_addr: String, + local_addr: Option, } impl Socket { fn new(fd: usercalls::raw::Fd, local_addr: String) -> Socket { - Socket { inner: Arc::new(FileDesc::new(fd)), local_addr } + Socket { inner: Arc::new(FileDesc::new(fd)), local_addr: Some(local_addr) } + } +} + +impl AsInner for Socket { + fn as_inner(&self) -> &FileDesc { &self.inner } +} + +impl TryIntoInner for Socket { + fn try_into_inner(self) -> Result { + let Socket { inner, local_addr } = self; + Arc::try_unwrap(inner).map_err(|inner| Socket { inner, local_addr } ) + } +} + +impl FromInner for Socket { + fn from_inner(inner: FileDesc) -> Socket { + Socket { inner: Arc::new(inner), local_addr: None } } } #[derive(Debug, Clone)] pub struct TcpStream { inner: Socket, - peer_addr: String, + peer_addr: Option, } fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result { @@ -53,16 +70,19 @@ fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result { } } -fn addr_to_sockaddr(addr: &str) -> io::Result { - // 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()) +fn addr_to_sockaddr(addr: &Option) -> io::Result { + addr.as_ref() + .ok_or(io::ErrorKind::AddrNotAvailable)? + .to_socket_addrs() + // unwrap OK: if an iterator is returned, we're guaranteed to get exactly one entry + .map(|mut it| it.next().unwrap()) } impl TcpStream { pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result { 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 }) + Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) }) } pub fn connect_timeout(addr: &SocketAddr, _: Duration) -> io::Result { @@ -138,6 +158,24 @@ impl TcpStream { } } +impl AsInner for TcpStream { + fn as_inner(&self) -> &Socket { &self.inner } +} + +// `Inner` includes `peer_addr` so that a `TcpStream` maybe correctly +// reconstructed if `Socket::try_into_inner` fails. +impl IntoInner<(Socket, Option)> for TcpStream { + fn into_inner(self) -> (Socket, Option) { + (self.inner, self.peer_addr) + } +} + +impl FromInner<(Socket, Option)> for TcpStream { + fn from_inner((inner, peer_addr): (Socket, Option)) -> TcpStream { + TcpStream { inner, peer_addr } + } +} + #[derive(Debug, Clone)] pub struct TcpListener { inner: Socket, @@ -156,6 +194,7 @@ impl TcpListener { pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { let (fd, local_addr, peer_addr) = usercalls::accept_stream(self.inner.inner.raw())?; + let peer_addr = Some(peer_addr); 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)) } @@ -189,6 +228,22 @@ impl TcpListener { } } +impl AsInner for TcpListener { + fn as_inner(&self) -> &Socket { &self.inner } +} + +impl IntoInner for TcpListener { + fn into_inner(self) -> Socket { + self.inner + } +} + +impl FromInner for TcpListener { + fn from_inner(inner: Socket) -> TcpListener { + TcpListener { inner } + } +} + pub struct UdpSocket(Void); impl UdpSocket {