Skip to content

Commit 15a2607

Browse files
committed
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 (#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 ```
2 parents a2fb99b + 7bea6a1 commit 15a2607

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+4978
-246
lines changed

.gitmodules

+3-1
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,12 @@
6161
path = src/tools/clang
6262
url = https://github.com/rust-lang-nursery/clang.git
6363
branch = rust-release-80-v2
64-
6564
[submodule "src/doc/rustc-guide"]
6665
path = src/doc/rustc-guide
6766
url = https://github.com/rust-lang/rustc-guide.git
6867
[submodule "src/doc/edition-guide"]
6968
path = src/doc/edition-guide
7069
url = https://github.com/rust-lang-nursery/edition-guide
70+
[submodule "src/rust-sgx"]
71+
path = src/rust-sgx
72+
url = https://github.com/fortanix/rust-sgx

Cargo.lock

+9
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,14 @@ name = "foreign-types-shared"
797797
version = "0.1.1"
798798
source = "registry+https://github.com/rust-lang/crates.io-index"
799799

800+
[[package]]
801+
name = "fortanix-sgx-abi"
802+
version = "0.0.0"
803+
dependencies = [
804+
"compiler_builtins 0.0.0",
805+
"core 0.0.0",
806+
]
807+
800808
[[package]]
801809
name = "fs2"
802810
version = "0.4.3"
@@ -2773,6 +2781,7 @@ dependencies = [
27732781
"compiler_builtins 0.0.0",
27742782
"core 0.0.0",
27752783
"dlmalloc 0.0.0",
2784+
"fortanix-sgx-abi 0.0.0",
27762785
"libc 0.0.0",
27772786
"panic_abort 0.0.0",
27782787
"panic_unwind 0.0.0",

src/bootstrap/dist.rs

+1
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,7 @@ impl Step for Src {
874874
"src/rustc/compiler_builtins_shim",
875875
"src/rustc/libc_shim",
876876
"src/rustc/dlmalloc_shim",
877+
"src/rustc/fortanix-sgx-abi_shim",
877878
"src/libtest",
878879
"src/libterm",
879880
"src/libprofiler_builtins",

src/liblibc

Submodule liblibc updated 65 files

src/libpanic_abort/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 {
6666
unsafe fn abort() -> ! {
6767
core::intrinsics::abort();
6868
}
69+
70+
#[cfg(target_env="sgx")]
71+
unsafe fn abort() -> ! {
72+
extern "C" { pub fn panic_exit() -> !; }
73+
panic_exit();
74+
}
6975
}
7076

7177
// This... is a bit of an oddity. The tl;dr; is that this is required to link

src/libpanic_unwind/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ cfg_if! {
6262
if #[cfg(target_os = "emscripten")] {
6363
#[path = "emcc.rs"]
6464
mod imp;
65-
} else if #[cfg(target_arch = "wasm32")] {
65+
} else if #[cfg(any(target_arch = "wasm32", target_env = "sgx"))] {
6666
#[path = "dummy.rs"]
6767
mod imp;
6868
} else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] {

src/libstd/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ rustc_lsan = { path = "../librustc_lsan" }
3535
rustc_msan = { path = "../librustc_msan" }
3636
rustc_tsan = { path = "../librustc_tsan" }
3737

38-
[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies]
38+
[target.'cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), target_env = "sgx"))'.dependencies]
3939
dlmalloc = { path = '../rustc/dlmalloc_shim' }
4040

41+
[target.x86_64-fortanix-unknown-sgx.dependencies]
42+
fortanix-sgx-abi = { path = "../rustc/fortanix-sgx-abi_shim" }
43+
4144
[build-dependencies]
4245
cc = "1.0"
4346
build_helper = { path = "../build_helper" }

src/libstd/io/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ pub enum ErrorKind {
184184
}
185185

186186
impl ErrorKind {
187-
fn as_str(&self) -> &'static str {
187+
pub(crate) fn as_str(&self) -> &'static str {
188188
match *self {
189189
ErrorKind::NotFound => "entity not found",
190190
ErrorKind::PermissionDenied => "permission denied",

src/libstd/io/lazy.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const fn done<T>() -> *mut Arc<T> { 1_usize as *mut _ }
2626
unsafe impl<T> Sync for Lazy<T> {}
2727

2828
impl<T> Lazy<T> {
29+
#[unstable(feature = "sys_internals", issue = "0")] // FIXME: min_const_fn
2930
pub const fn new() -> Lazy<T> {
3031
Lazy {
3132
lock: Mutex::new(),

src/libstd/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@
312312
#![feature(non_exhaustive)]
313313
#![feature(alloc_layout_extra)]
314314
#![feature(maybe_uninit)]
315+
#![cfg_attr(target_env = "sgx", feature(global_asm, range_contains, slice_index_methods,
316+
decl_macro, coerce_unsized))]
315317

316318
#![default_lib_allocator]
317319

@@ -354,6 +356,12 @@ extern crate unwind;
354356
// testing gives test-std access to real-std lang items and globals. See #2912
355357
#[cfg(test)] extern crate std as realstd;
356358

359+
#[cfg(target_env = "sgx")]
360+
#[macro_use]
361+
#[allow(unused_imports)] // FIXME: without `#[macro_use]`, get error: “cannot
362+
// determine resolution for the macro `usercalls_asm`”
363+
extern crate fortanix_sgx_abi;
364+
357365
// The standard macros that are not built-in to the compiler.
358366
#[macro_use]
359367
mod macros;

src/libstd/net/addr.rs

+7-21
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ use net::{ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr};
1616
use option;
1717
use sys::net::netc as c;
1818
use sys_common::{FromInner, AsInner, IntoInner};
19-
use sys_common::net::lookup_host;
19+
use sys_common::net::LookupHost;
2020
use vec;
2121
use iter;
2222
use slice;
23+
use convert::TryInto;
2324

2425
/// An internet socket address, either IPv4 or IPv6.
2526
///
@@ -863,9 +864,9 @@ impl ToSocketAddrs for (Ipv6Addr, u16) {
863864
}
864865
}
865866

866-
fn resolve_socket_addr(s: &str, p: u16) -> io::Result<vec::IntoIter<SocketAddr>> {
867-
let ips = lookup_host(s)?;
868-
let v: Vec<_> = ips.map(|mut a| { a.set_port(p); a }).collect();
867+
fn resolve_socket_addr(lh: LookupHost) -> io::Result<vec::IntoIter<SocketAddr>> {
868+
let p = lh.port();
869+
let v: Vec<_> = lh.map(|mut a| { a.set_port(p); a }).collect();
869870
Ok(v.into_iter())
870871
}
871872

@@ -885,7 +886,7 @@ impl<'a> ToSocketAddrs for (&'a str, u16) {
885886
return Ok(vec![SocketAddr::V6(addr)].into_iter())
886887
}
887888

888-
resolve_socket_addr(host, port)
889+
resolve_socket_addr((host, port).try_into()?)
889890
}
890891
}
891892

@@ -899,22 +900,7 @@ impl ToSocketAddrs for str {
899900
return Ok(vec![addr].into_iter());
900901
}
901902

902-
macro_rules! try_opt {
903-
($e:expr, $msg:expr) => (
904-
match $e {
905-
Some(r) => r,
906-
None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
907-
$msg)),
908-
}
909-
)
910-
}
911-
912-
// split the string by ':' and convert the second part to u16
913-
let mut parts_iter = self.rsplitn(2, ':');
914-
let port_str = try_opt!(parts_iter.next(), "invalid socket address");
915-
let host = try_opt!(parts_iter.next(), "invalid socket address");
916-
let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
917-
resolve_socket_addr(host, port)
903+
resolve_socket_addr(self.try_into()?)
918904
}
919905
}
920906

src/libstd/net/mod.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,15 @@ fn hton<I: NetInt>(i: I) -> I { i.to_be() }
112112
fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }
113113

114114
fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
115-
where F: FnMut(&SocketAddr) -> io::Result<T>
115+
where F: FnMut(io::Result<&SocketAddr>) -> io::Result<T>
116116
{
117+
let addrs = match addr.to_socket_addrs() {
118+
Ok(addrs) => addrs,
119+
Err(e) => return f(Err(e))
120+
};
117121
let mut last_err = None;
118-
for addr in addr.to_socket_addrs()? {
119-
match f(&addr) {
122+
for addr in addrs {
123+
match f(Ok(&addr)) {
120124
Ok(l) => return Ok(l),
121125
Err(e) => last_err = Some(e),
122126
}

src/libstd/panicking.rs

+11-15
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use intrinsics;
2929
use mem;
3030
use ptr;
3131
use raw;
32-
use sys::stdio::{Stderr, stderr_prints_nothing};
32+
use sys::stdio::panic_output;
3333
use sys_common::rwlock::RWLock;
3434
use sys_common::thread_info;
3535
use sys_common::util;
@@ -193,7 +193,6 @@ fn default_hook(info: &PanicInfo) {
193193
None => "Box<Any>",
194194
}
195195
};
196-
let mut err = Stderr::new().ok();
197196
let thread = thread_info::current_thread();
198197
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
199198

@@ -215,17 +214,14 @@ fn default_hook(info: &PanicInfo) {
215214
}
216215
};
217216

218-
let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
219-
match (prev, err.as_mut()) {
220-
(Some(mut stderr), _) => {
221-
write(&mut *stderr);
222-
let mut s = Some(stderr);
223-
LOCAL_STDERR.with(|slot| {
224-
*slot.borrow_mut() = s.take();
225-
});
226-
}
227-
(None, Some(ref mut err)) => { write(err) }
228-
_ => {}
217+
if let Some(mut local) = LOCAL_STDERR.with(|s| s.borrow_mut().take()) {
218+
write(&mut *local);
219+
let mut s = Some(local);
220+
LOCAL_STDERR.with(|slot| {
221+
*slot.borrow_mut() = s.take();
222+
});
223+
} else if let Some(mut out) = panic_output() {
224+
write(&mut out);
229225
}
230226
}
231227

@@ -485,7 +481,7 @@ fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
485481
// Some platforms know that printing to stderr won't ever actually
486482
// print anything, and if that's the case we can skip the default
487483
// hook.
488-
Hook::Default if stderr_prints_nothing() => {}
484+
Hook::Default if panic_output().is_none() => {}
489485
Hook::Default => {
490486
info.set_payload(payload.get());
491487
default_hook(&info);
@@ -494,7 +490,7 @@ fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
494490
info.set_payload(payload.get());
495491
(*ptr)(&info);
496492
}
497-
}
493+
};
498494
HOOK_LOCK.read_unlock();
499495
}
500496

src/libstd/sys/cloudabi/shims/net.rs

+25-6
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ use io;
1313
use net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
1414
use time::Duration;
1515
use sys::{unsupported, Void};
16+
use convert::TryFrom;
1617

1718
pub extern crate libc as netc;
1819

1920
pub struct TcpStream(Void);
2021

2122
impl TcpStream {
22-
pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> {
23+
pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
2324
unsupported()
2425
}
2526

@@ -105,7 +106,7 @@ impl fmt::Debug for TcpStream {
105106
pub struct TcpListener(Void);
106107

107108
impl TcpListener {
108-
pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> {
109+
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
109110
unsupported()
110111
}
111112

@@ -155,7 +156,7 @@ impl fmt::Debug for TcpListener {
155156
pub struct UdpSocket(Void);
156157

157158
impl UdpSocket {
158-
pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> {
159+
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
159160
unsupported()
160161
}
161162

@@ -271,7 +272,7 @@ impl UdpSocket {
271272
match self.0 {}
272273
}
273274

274-
pub fn connect(&self, _: &SocketAddr) -> io::Result<()> {
275+
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
275276
match self.0 {}
276277
}
277278
}
@@ -284,13 +285,31 @@ impl fmt::Debug for UdpSocket {
284285

285286
pub struct LookupHost(Void);
286287

288+
impl LookupHost {
289+
pub fn port(&self) -> u16 {
290+
match self.0 {}
291+
}
292+
}
293+
287294
impl Iterator for LookupHost {
288295
type Item = SocketAddr;
289296
fn next(&mut self) -> Option<SocketAddr> {
290297
match self.0 {}
291298
}
292299
}
293300

294-
pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
295-
unsupported()
301+
impl<'a> TryFrom<&'a str> for LookupHost {
302+
type Error = io::Error;
303+
304+
fn try_from(_v: &'a str) -> io::Result<LookupHost> {
305+
unsupported()
306+
}
307+
}
308+
309+
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
310+
type Error = io::Error;
311+
312+
fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
313+
unsupported()
314+
}
296315
}

src/libstd/sys/cloudabi/stdio.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,6 @@ pub fn is_ebadf(err: &io::Error) -> bool {
7878

7979
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
8080

81-
pub fn stderr_prints_nothing() -> bool {
82-
false
81+
pub fn panic_output() -> Option<impl io::Write> {
82+
Stderr::new().ok()
8383
}

src/libstd/sys/cloudabi/thread.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ unsafe impl Send for Thread {}
3232
unsafe impl Sync for Thread {}
3333

3434
impl Thread {
35-
pub unsafe fn new<'a>(stack: usize, p: Box<dyn FnBox() + 'a>) -> io::Result<Thread> {
35+
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
36+
pub unsafe fn new(stack: usize, p: Box<dyn FnBox()>) -> io::Result<Thread> {
3637
let p = box p;
3738
let mut native: libc::pthread_t = mem::zeroed();
3839
let mut attr: libc::pthread_attr_t = mem::zeroed();

src/libstd/sys/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ cfg_if! {
4848
} else if #[cfg(target_arch = "wasm32")] {
4949
mod wasm;
5050
pub use self::wasm::*;
51+
} else if #[cfg(target_env = "sgx")] {
52+
mod sgx;
53+
pub use self::sgx::*;
5154
} else {
5255
compile_error!("libstd doesn't compile for this platform yet");
5356
}

0 commit comments

Comments
 (0)