Auto merge of #57119 - jethrogb:jb/sgx-os-mod2, r=joshtriplett
Add `io` and `arch` modules to `std::os::fortanix_sgx` This PR adds two more (unstable) modules to `std::os::fortanix_sgx` for the `x86_64-fortanix-unknown-sgx` target. ### io `io` allows conversion between raw file descriptors and Rust types, similar to `std::os::unix::io`. ### arch `arch` exposes the `ENCLU[EREPORT]` and `ENCLU[EGETKEY]` instructions. The current functions are very likely not going to be the final form of these functions (see also https://github.com/fortanix/rust-sgx/issues/15), but this should be sufficient to enable experimentation in libraries. I tried using the actual types (from the [`sgx-isa` crate](https://crates.io/crates/sgx-isa)) instead of byte arrays, but that would make `std` dependent on the `bitflags` crate which I didn't want to do at this time.
This commit is contained in:
commit
d2986970ad
@ -304,7 +304,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]
|
||||
|
||||
|
@ -55,3 +55,5 @@ pub mod usercalls {
|
||||
pub mod mem {
|
||||
pub use sys::abi::mem::*;
|
||||
}
|
||||
|
||||
pub use sys::ext::{io, arch};
|
||||
|
84
src/libstd/sys/sgx/ext/arch.rs
Normal file
84
src/libstd/sys/sgx/ext/arch.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T>(pub T);
|
||||
|
||||
/// Wrapper struct to force 128-byte alignment.
|
||||
#[repr(align(128))]
|
||||
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||
pub struct Align128<T>(pub T);
|
||||
|
||||
/// Wrapper struct to force 512-byte alignment.
|
||||
#[repr(align(512))]
|
||||
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||
pub struct Align512<T>(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<Align16<[u8; 16]>, 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()
|
||||
}
|
||||
}
|
119
src/libstd/sys/sgx/ext/io.rs
Normal file
119
src/libstd/sys/sgx/ext/io.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<RawFd, Self>;
|
||||
}
|
||||
|
||||
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<RawFd, Self> {
|
||||
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<RawFd, Self> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
src/libstd/sys/sgx/ext/mod.rs
Normal file
14
src/libstd/sys/sgx/ext/mod.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;
|
@ -2,7 +2,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)]
|
||||
@ -41,6 +41,20 @@ impl AsInner<Fd> for FileDesc {
|
||||
fn as_inner(&self) -> &Fd { &self.fd }
|
||||
}
|
||||
|
||||
impl IntoInner<Fd> for FileDesc {
|
||||
fn into_inner(self) -> Fd {
|
||||
let fd = self.fd;
|
||||
mem::forget(self);
|
||||
fd
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<Fd> for FileDesc {
|
||||
fn from_inner(fd: Fd) -> FileDesc {
|
||||
FileDesc { fd }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FileDesc {
|
||||
fn drop(&mut self) {
|
||||
usercalls::close(self.fd)
|
||||
|
@ -17,6 +17,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;
|
||||
@ -141,3 +142,9 @@ pub fn hashmap_random_keys() -> (u64, u64) {
|
||||
}
|
||||
(rdrand64(), rdrand64())
|
||||
}
|
||||
|
||||
pub use sys_common::{AsInner, FromInner, IntoInner};
|
||||
|
||||
pub trait TryIntoInner<Inner>: Sized {
|
||||
fn try_into_inner(self) -> Result<Inner, Self>;
|
||||
}
|
||||
|
@ -2,7 +2,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;
|
||||
@ -13,21 +13,38 @@ use super::abi::usercalls;
|
||||
const DEFAULT_FAKE_TTL: u32 = 64;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Socket {
|
||||
pub struct Socket {
|
||||
inner: Arc<FileDesc>,
|
||||
local_addr: String,
|
||||
local_addr: Option<String>,
|
||||
}
|
||||
|
||||
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<FileDesc> for Socket {
|
||||
fn as_inner(&self) -> &FileDesc { &self.inner }
|
||||
}
|
||||
|
||||
impl TryIntoInner<FileDesc> for Socket {
|
||||
fn try_into_inner(self) -> Result<FileDesc, Socket> {
|
||||
let Socket { inner, local_addr } = self;
|
||||
Arc::try_unwrap(inner).map_err(|inner| Socket { inner, local_addr } )
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<FileDesc> 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<String>,
|
||||
}
|
||||
|
||||
fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> {
|
||||
@ -43,16 +60,19 @@ fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> {
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
fn addr_to_sockaddr(addr: &Option<String>) -> io::Result<SocketAddr> {
|
||||
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<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 })
|
||||
Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) })
|
||||
}
|
||||
|
||||
pub fn connect_timeout(addr: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
|
||||
@ -128,6 +148,24 @@ impl TcpStream {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<Socket> 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<String>)> for TcpStream {
|
||||
fn into_inner(self) -> (Socket, Option<String>) {
|
||||
(self.inner, self.peer_addr)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<(Socket, Option<String>)> for TcpStream {
|
||||
fn from_inner((inner, peer_addr): (Socket, Option<String>)) -> TcpStream {
|
||||
TcpStream { inner, peer_addr }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TcpListener {
|
||||
inner: Socket,
|
||||
@ -146,6 +184,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))
|
||||
}
|
||||
@ -179,6 +218,22 @@ impl TcpListener {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<Socket> for TcpListener {
|
||||
fn as_inner(&self) -> &Socket { &self.inner }
|
||||
}
|
||||
|
||||
impl IntoInner<Socket> for TcpListener {
|
||||
fn into_inner(self) -> Socket {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<Socket> for TcpListener {
|
||||
fn from_inner(inner: Socket) -> TcpListener {
|
||||
TcpListener { inner }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UdpSocket(Void);
|
||||
|
||||
impl UdpSocket {
|
||||
|
Loading…
Reference in New Issue
Block a user