From 41ae223d6458db488b938927015c643720b416ef Mon Sep 17 00:00:00 2001 From: Christopher Schramm Date: Thu, 3 Feb 2022 17:20:46 +0100 Subject: [PATCH] Build sgx_tstd as drop-in std replacement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Motivation: There are two basic strategies to use teaclave with existing Rust crates: * Opt into no_std (+ alloc). This restricts the usable crates to those with no_std support and patched ones that work without it if adapted accordingly and that is actually a huge restriction. Also, it just does not reflect the situation as sgx_tstd is a proper std, just not 100 % complete compared to std and using a different naming. * Port all dependencies to explicit sgx_tstd support, mostly adding things like "use sgx_tstd as std;". This means manual work for everyting and especially a lot of maintenance hassle. Strategy 3: Use sgx_tstd as a drop-in replacement for std. This turned out to work decently. With the current state you can build (note that I'm not saying "run" 😅) the current kitx main with just an extra rustc flag and one small patch (see below). Steps taken: * Rename the sgx_tstd lib to just std. * Build a sysroot with it and its dependencies. * Improve std-compatibility as far as necessary. Building the sysroot is done by the build_sysroot.sh script, meant to be run in the sgx_tstd directory and taking the desired target path as an optional argument (../../sysroot otherwise). It leverages cargo's -Z build-std feature to build the core and alloc crates. panic_unwind could be added there as well but is currently included by adding the one from the sgx_panic_unwind directory as a dependency (I have no idea what the difference might be as there is no dependency on std anyway). Enabled features for improved compatibility: * thread and backtrace - they should be uncritical, thread is linked by a lot of crates, backtrace only marginally but at least anyhow expects it to be available in nightlies. * net - is considered untrusted but will probably be inevitable. We will need to audit and monitor which dependencies use its API and what they do with it. * untrusted_time and untrusted_fs - similar to net but we might not actually need their API. We will want to disable them in the long run, probably by patching dependencies or providing stub implementations of the affected API. I will gather a list of usages in current kitx dependencies to find a strategy for this. Patches for improved compatibility: * Re-export ::core::arch as arch * Re-export some of the sync::Sgx* structures under their std names. * Re-export thread::SgxThread as thread::Thread. * Implement thread::Builder::stack_size - a pointless noop just for API compatibility. * Implement stubs for process::{ChildStdin, ChildStdout, ChildStderr}. These will fail if they are actually called. * Implement process::abort with the actual implementation from std. Caveats: * Obviously the provided std is incomplete. Most notably it does not have std::process (apart from the patches mentioned above). * The sysroot does not have a proc_macro crate. kitx builds fine without it (however, do not try to e.g. cargo build -p proc-macro2). * An explicit target is required when building, even if it's the default. Without a target, e.g. the syn crate's build.rs fails to build due to the missing std::process::Command. I do not get why this does not happen when providing a target, to be honest. * At least the sgx-sdk nix package only has a static version of libsgx_tstdc and others in $SGX_SDK/lib, so building cdylibs will fail. For the kitx workspace the last point means that you need to patch out crate-type cdylib from hyper's Cargo.toml (there is active work going on to remove it in general: https://github.com/hyperium/hyper/issues/2685) but that is the only change necessary. It is also not possible to build the C and JNI binding crates for the same reason. --- sgx_tstd/Cargo.toml | 3 ++- sgx_tstd/build_sysroot.sh | 17 +++++++++++++++++ sgx_tstd/src/lib.rs | 2 ++ sgx_tstd/src/process.rs | 28 ++++++++++++++++++++++++++++ sgx_tstd/src/sync/mod.rs | 5 +++++ sgx_tstd/src/thread/mod.rs | 6 ++++++ 6 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 sgx_tstd/build_sysroot.sh create mode 100644 sgx_tstd/src/process.rs diff --git a/sgx_tstd/Cargo.toml b/sgx_tstd/Cargo.toml index 2d27a6e38..89a81483f 100644 --- a/sgx_tstd/Cargo.toml +++ b/sgx_tstd/Cargo.toml @@ -9,7 +9,7 @@ description = "Rust SGX SDK provides the ability to write Intel SGX applications edition = "2018" [lib] -name = "sgx_tstd" +name = "std" crate-type = ["rlib"] [features] @@ -31,6 +31,7 @@ sgx_tprotected_fs = { path = "../sgx_tprotected_fs" } sgx_backtrace_sys = { path = "../sgx_backtrace_sys" } sgx_demangle = { path = "../sgx_demangle" } sgx_unwind = { path = "../sgx_unwind" } +panic_unwind = { path = "../sgx_panic_unwind" } [dependencies.hashbrown] package = "hashbrown_tstd" diff --git a/sgx_tstd/build_sysroot.sh b/sgx_tstd/build_sysroot.sh new file mode 100644 index 000000000..17481861a --- /dev/null +++ b/sgx_tstd/build_sysroot.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +SYSROOT_PATH="${1:-$(realpath ../../sysroot)}" +export CARGO_BUILD_TARGET="${CARGO_BUILD_TARGET:-$(rustc -vV | sed -n 's|host: ||p')}" +RUSTUP_TOOLCHAIN="${RUSTUP_TOOLCHAIN:-$(rustup show active-toolchain | cut -d' ' -f1)}" + +cargo clean --target "$CARGO_BUILD_TARGET" +cargo build --release -Z build-std=core,alloc --features net,untrusted_time,untrusted_fs,thread,backtrace + +mkdir -p "$SYSROOT_PATH/lib/rustlib/$CARGO_BUILD_TARGET" +rm -Rf "$SYSROOT_PATH/lib/rustlib/$CARGO_BUILD_TARGET/lib" +cp -R "$PWD/target/$CARGO_BUILD_TARGET/release/deps" "$SYSROOT_PATH/lib/rustlib/$CARGO_BUILD_TARGET/lib" + +echo "Here's your environment:" +echo RUSTFLAGS=\"--sysroot $SYSROOT_PATH\" CARGO_BUILD_TARGET=\"$CARGO_BUILD_TARGET\" RUSTUP_TOOLCHAIN=\"$RUSTUP_TOOLCHAIN\" diff --git a/sgx_tstd/src/lib.rs b/sgx_tstd/src/lib.rs index 7f3b01813..b3f864e19 100644 --- a/sgx_tstd/src/lib.rs +++ b/sgx_tstd/src/lib.rs @@ -188,6 +188,7 @@ pub use alloc_crate::str; pub use alloc_crate::string; pub use alloc_crate::vec; pub use core::any; +pub use core::arch; pub use core::array; pub use core::cell; pub use core::char; @@ -240,6 +241,7 @@ pub mod num; pub mod os; pub mod panic; pub mod path; +pub mod process; pub mod sync; pub mod time; pub mod enclave; diff --git a/sgx_tstd/src/process.rs b/sgx_tstd/src/process.rs new file mode 100644 index 000000000..ea42d589d --- /dev/null +++ b/sgx_tstd/src/process.rs @@ -0,0 +1,28 @@ +use crate::os::unix::io::{IntoRawFd, RawFd}; + +pub struct ChildStdin; +pub struct ChildStdout; +pub struct ChildStderr; + +impl IntoRawFd for ChildStdin { + fn into_raw_fd(self) -> RawFd { + unimplemented!() + } +} + +impl IntoRawFd for ChildStdout { + fn into_raw_fd(self) -> RawFd { + unimplemented!() + } +} + +impl IntoRawFd for ChildStderr { + fn into_raw_fd(self) -> RawFd { + unimplemented!() + } +} + +#[cold] +pub fn abort() -> ! { + crate::sys::abort_internal(); +} diff --git a/sgx_tstd/src/sync/mod.rs b/sgx_tstd/src/sync/mod.rs index 1d52d16a3..c9b8a28d1 100644 --- a/sgx_tstd/src/sync/mod.rs +++ b/sgx_tstd/src/sync/mod.rs @@ -38,6 +38,11 @@ pub use self::poison::{LockResult, PoisonError, TryLockError, TryLockResult}; pub use self::rwlock::{SgxRwLock, SgxRwLockReadGuard, SgxRwLockWriteGuard, SgxThreadRwLock}; pub use self::spinlock::{SgxSpinlock, SgxSpinlockGuard, SgxThreadSpinlock}; +pub use { + SgxCondvar as Condvar, SgxMutex as Mutex, SgxMutexGuard as MutexGuard, SgxRwLock as RwLock, + SgxRwLockReadGuard as RwLockReadGuard, +}; + #[cfg(feature = "thread")] pub mod mpsc; diff --git a/sgx_tstd/src/thread/mod.rs b/sgx_tstd/src/thread/mod.rs index 33fe85400..78c0633a4 100644 --- a/sgx_tstd/src/thread/mod.rs +++ b/sgx_tstd/src/thread/mod.rs @@ -173,6 +173,10 @@ impl Builder { self } + pub fn stack_size(self, _size: usize) -> Builder { + self + } + /// Spawns a new thread by taking ownership of the `Builder`, and returns an /// [`io::Result`] to its [`JoinHandle`]. /// @@ -879,6 +883,8 @@ pub struct SgxThread { inner: Arc, } +pub use SgxThread as Thread; + impl SgxThread { // Used only internally to construct a thread object without spawning // Panics if the name contains nuls.