about summary refs log tree commit diff
path: root/src/libstd/sys_common
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-12-07 06:34:16 +0000
committerbors <bors@rust-lang.org>2018-12-07 06:34:16 +0000
commit15a2607863fded7570cacfc7825702dde5a4234c (patch)
treec27f5e06b985789b7e6f75c63eded958fe0b643f /src/libstd/sys_common
parenta2fb99bc17527798aeeef1d7ccc61811a9362131 (diff)
parent7bea6a19641118937781d7971ba96e8d4a81497c (diff)
downloadrust-15a2607863fded7570cacfc7825702dde5a4234c.tar.gz
rust-15a2607863fded7570cacfc7825702dde5a4234c.zip
Auto merge of #56066 - jethrogb:jb/sgx-target, r=alexcrichton
Add SGX target to std and dependencies

This PR adds tier 3 `std` support for the `x86_64-fortanix-unknown-sgx` target.

### Background

Intel Software Guard Extensions (SGX) is an instruction set extension for x86 that allows executing code in fully-isolated *secure enclaves*. These enclaves reside in the address space of a regular user process, but access to the enclave's address space from outside (by e.g. the OS or a hypervisor) is blocked.

From within such enclaves, there is no access to the operating system or hardware peripherals. In order to communicate with the outside world, enclaves require an untrusted “helper” program that runs as a normal user process.

SGX is **not** a sandboxing technology: code inside SGX has full access to all memory belonging to the process it is running in.

### Overview

The Fortanix SGX ABI (compiler target `x86_64-fortanix-unknown-sgx`) is an interface for Intel SGX enclaves. It is a small yet functional interface suitable for writing larger enclaves. In contrast to other enclave interfaces, this interface is primarly designed for running entire applications in an enclave. The interface has been under development since early 2016 and builds on Fortanix's significant experience running enclaves in production.

Also unlike other enclave interfaces, this is the only implementation of an enclave interface that is nearly pure-Rust (except for the entry point code).

A description of the ABI may be found at https://docs.rs/fortanix-sgx-abi/ and https://github.com/fortanix/rust-sgx/blob/master/doc/FORTANIX-SGX-ABI.md.

The following parts of `std` are not supported and most operations will error when used:

* `std::fs`
* `std::process`
* `std::net::UdpSocket`

### Future plans

A separate PR (https://github.com/rust-lang/rust/pull/56067/) will add the SGX target to the rust compiler. In the very near future, I expect to upgrade this target to tier 2.

This PR is just the initial support to make things mostly work. There will be more work coming in the future, for example to add interfaces to the native SGX primitives, implement unwinding, optimize usercalls.

UDP and some form of filesystem support may be added in the future, but process support seems unlikely given the platform's constraints.

### Testing build

1. Install [Xargo](https://github.com/japaric/xargo): `cargo install xargo`
2. Create a new Cargo project, for example: `cargo new --bin sgxtest`.
3. Put the following in a file `Xargo.toml` next to your `Cargo.toml`:

```toml
[target.x86_64-fortanix-unknown-sgx.dependencies.std]
git = "https://github.com/jethrogb/rust"
branch = "jb/sgx-target"
```

NB. This can be quite slow. Instead, you can have a local checkout of that branch and use `path = "/path/to/rust/src/libstd"` instead. Don't forget to checkout the submodules too!

4. Build:

```sh
xargo build --target x86_64-fortanix-unknown-sgx
```

### Testing execution

Execution is currently only supported on x86-64 Linux, but support for Windows is planned.

1. Install pre-requisites. In order to test execution, you'll need to have a CPU with Intel SGX support. SGX support needs to be enabled in the BIOS. You'll also need to install the SGX driver and Platform Software (PSW) from [Intel](https://01.org/intel-software-guard-extensions).

2. Install toolchain, executor:
```sh
cargo install sgxs-tools --version 0.6.0-rc1
cargo install fortanix-sgx-tools --version 0.1.0-rc1
```

3. Start the enclave:

```sh
ftxsgx-elf2sgxs target/x86_64-fortanix-unknown-sgx/debug/sgxtest --heap-size 0x20000 --ssaframesize 1 --stack-size 0x20000 --threads 1 --debug
sgxs-append -i target/x86_64-fortanix-unknown-sgx/debug/sgxtest.sgxs
ftxsgx-runner target/x86_64-fortanix-unknown-sgx/debug/sgxtest.sgxs
```
Diffstat (limited to 'src/libstd/sys_common')
-rw-r--r--src/libstd/sys_common/condvar.rs1
-rw-r--r--src/libstd/sys_common/mod.rs8
-rw-r--r--src/libstd/sys_common/mutex.rs1
-rw-r--r--src/libstd/sys_common/net.rs74
-rw-r--r--src/libstd/sys_common/rwlock.rs1
-rw-r--r--src/libstd/sys_common/util.rs7
6 files changed, 69 insertions, 23 deletions
diff --git a/src/libstd/sys_common/condvar.rs b/src/libstd/sys_common/condvar.rs
index b6f29dd5fc3..16bf0803a8d 100644
--- a/src/libstd/sys_common/condvar.rs
+++ b/src/libstd/sys_common/condvar.rs
@@ -25,6 +25,7 @@ impl Condvar {
     ///
     /// Behavior is undefined if the condition variable is moved after it is
     /// first used with any of the functions below.
+    #[unstable(feature = "sys_internals", issue = "0")] // FIXME: min_const_fn
     pub const fn new() -> Condvar { Condvar(imp::Condvar::new()) }
 
     /// Prepares the condition variable for use.
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index 4b8cde3d1f4..881794d9f16 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -57,9 +57,11 @@ pub mod bytestring;
 pub mod process;
 
 cfg_if! {
-    if #[cfg(any(target_os = "cloudabi", target_os = "l4re", target_os = "redox"))] {
-        pub use sys::net;
-    } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] {
+    if #[cfg(any(target_os = "cloudabi",
+                 target_os = "l4re",
+                 target_os = "redox",
+                 all(target_arch = "wasm32", not(target_os = "emscripten")),
+                 target_env = "sgx"))] {
         pub use sys::net;
     } else {
         pub mod net;
diff --git a/src/libstd/sys_common/mutex.rs b/src/libstd/sys_common/mutex.rs
index c6d531c7a1a..87684237638 100644
--- a/src/libstd/sys_common/mutex.rs
+++ b/src/libstd/sys_common/mutex.rs
@@ -27,6 +27,7 @@ impl Mutex {
     /// Also, until `init` is called, behavior is undefined if this
     /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock`
     /// are called by the thread currently holding the lock.
+    #[unstable(feature = "sys_internals", issue = "0")] // FIXME: min_const_fn
     pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) }
 
     /// Prepare the mutex for use.
diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs
index d09a233ed89..dce2bf71cec 100644
--- a/src/libstd/sys_common/net.rs
+++ b/src/libstd/sys_common/net.rs
@@ -20,6 +20,7 @@ use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
 use sys::net::netc as c;
 use sys_common::{AsInner, FromInner, IntoInner};
 use time::Duration;
+use convert::{TryFrom, TryInto};
 
 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
           target_os = "ios", target_os = "macos",
@@ -129,6 +130,13 @@ fn to_ipv6mr_interface(value: u32) -> ::libc::c_uint {
 pub struct LookupHost {
     original: *mut c::addrinfo,
     cur: *mut c::addrinfo,
+    port: u16
+}
+
+impl LookupHost {
+    pub fn port(&self) -> u16 {
+        self.port
+    }
 }
 
 impl Iterator for LookupHost {
@@ -158,17 +166,45 @@ impl Drop for LookupHost {
     }
 }
 
-pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
-    init();
+impl<'a> TryFrom<&'a str> for LookupHost {
+    type Error = io::Error;
 
-    let c_host = CString::new(host)?;
-    let mut hints: c::addrinfo = unsafe { mem::zeroed() };
-    hints.ai_socktype = c::SOCK_STREAM;
-    let mut res = ptr::null_mut();
-    unsafe {
-        cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)).map(|_| {
-            LookupHost { original: res, cur: res }
-        })
+    fn try_from(s: &str) -> io::Result<LookupHost> {
+        macro_rules! try_opt {
+            ($e:expr, $msg:expr) => (
+                match $e {
+                    Some(r) => r,
+                    None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                                      $msg)),
+                }
+            )
+        }
+
+        // split the string by ':' and convert the second part to u16
+        let mut parts_iter = s.rsplitn(2, ':');
+        let port_str = try_opt!(parts_iter.next(), "invalid socket address");
+        let host = try_opt!(parts_iter.next(), "invalid socket address");
+        let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
+
+        (host, port).try_into()
+    }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
+        init();
+
+        let c_host = CString::new(host)?;
+        let mut hints: c::addrinfo = unsafe { mem::zeroed() };
+        hints.ai_socktype = c::SOCK_STREAM;
+        let mut res = ptr::null_mut();
+        unsafe {
+            cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)).map(|_| {
+                LookupHost { original: res, cur: res, port }
+            })
+        }
     }
 }
 
@@ -181,7 +217,9 @@ pub struct TcpStream {
 }
 
 impl TcpStream {
-    pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
+    pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+        let addr = addr?;
+
         init();
 
         let sock = Socket::new(addr, c::SOCK_STREAM)?;
@@ -317,7 +355,9 @@ pub struct TcpListener {
 }
 
 impl TcpListener {
-    pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
+    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+        let addr = addr?;
+
         init();
 
         let sock = Socket::new(addr, c::SOCK_STREAM)?;
@@ -418,7 +458,9 @@ pub struct UdpSocket {
 }
 
 impl UdpSocket {
-    pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
+    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+        let addr = addr?;
+
         init();
 
         let sock = Socket::new(addr, c::SOCK_DGRAM)?;
@@ -584,8 +626,8 @@ impl UdpSocket {
         Ok(ret as usize)
     }
 
-    pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
-        let (addrp, len) = addr.into_inner();
+    pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> {
+        let (addrp, len) = addr?.into_inner();
         cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(|_| ())
     }
 }
@@ -618,7 +660,7 @@ mod tests {
     #[test]
     fn no_lookup_host_duplicates() {
         let mut addrs = HashMap::new();
-        let lh = match lookup_host("localhost") {
+        let lh = match LookupHost::try_from(("localhost", 0)) {
             Ok(lh) => lh,
             Err(e) => panic!("couldn't resolve `localhost': {}", e)
         };
diff --git a/src/libstd/sys_common/rwlock.rs b/src/libstd/sys_common/rwlock.rs
index 71a4f01ec4c..a430c254d3c 100644
--- a/src/libstd/sys_common/rwlock.rs
+++ b/src/libstd/sys_common/rwlock.rs
@@ -22,6 +22,7 @@ impl RWLock {
     ///
     /// Behavior is undefined if the reader-writer lock is moved after it is
     /// first used with any of the functions below.
+    #[unstable(feature = "sys_internals", issue = "0")] // FIXME: min_const_fn
     pub const fn new() -> RWLock { RWLock(imp::RWLock::new()) }
 
     /// Acquires shared access to the underlying lock, blocking the current
diff --git a/src/libstd/sys_common/util.rs b/src/libstd/sys_common/util.rs
index a373e980b97..fc86a59d17f 100644
--- a/src/libstd/sys_common/util.rs
+++ b/src/libstd/sys_common/util.rs
@@ -10,14 +10,13 @@
 
 use fmt;
 use io::prelude::*;
-use sys::stdio::{Stderr, stderr_prints_nothing};
+use sys::stdio::panic_output;
 use thread;
 
 pub fn dumb_print(args: fmt::Arguments) {
-    if stderr_prints_nothing() {
-        return
+    if let Some(mut out) = panic_output() {
+        let _ = out.write_fmt(args);
     }
-    let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
 }
 
 // Other platforms should use the appropriate platform-specific mechanism for