Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support letting enclaves do time keeping #660

Merged
merged 1 commit into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion intel-sgx/async-usercalls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ categories = ["asynchronous"]
[dependencies]
# Project dependencies
ipc-queue = { version = "0.3", path = "../../ipc-queue" }
fortanix-sgx-abi = { version = "0.5.0", path = "../fortanix-sgx-abi" }
fortanix-sgx-abi = { version = "0.6.0", path = "../fortanix-sgx-abi" }

# External dependencies
lazy_static = "1.4.0" # MIT/Apache-2.0
Expand Down
28 changes: 15 additions & 13 deletions intel-sgx/async-usercalls/src/callback.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use fortanix_sgx_abi::{invoke_with_usercalls, Fd, Result};
use fortanix_sgx_abi::{invoke_with_usercalls, Fd, Result, InsecureTimeInfo};
use std::io;
use std::os::fortanix_sgx::usercalls::raw::{Return, ReturnValue};
use std::os::fortanix_sgx::usercalls::FromSgxResult;
Expand All @@ -21,21 +21,23 @@ impl<F, T> From<F> for CbFn<T>
}

macro_rules! cbfn_type {
( ) => { CbFn<()> };
( -> ! ) => { () };
( -> u64 ) => { CbFn<u64> };
( -> (Result, usize) ) => { CbFn<io::Result<usize>> };
( -> (Result, u64) ) => { CbFn<io::Result<u64>> };
( -> (Result, Fd) ) => { CbFn<io::Result<Fd>> };
( -> (Result, *mut u8) ) => { CbFn<io::Result<*mut u8>> };
( -> Result ) => { CbFn<io::Result<()>> };
( ) => { CbFn<()> };
( -> ! ) => { () };
( -> u64 ) => { CbFn<u64> };
( -> (u64, *const InsecureTimeInfo) ) => { CbFn<(u64, *const InsecureTimeInfo)> };
( -> (Result, usize) ) => { CbFn<io::Result<usize>> };
( -> (Result, u64) ) => { CbFn<io::Result<u64>> };
( -> (Result, Fd) ) => { CbFn<io::Result<Fd>> };
( -> (Result, *mut u8) ) => { CbFn<io::Result<*mut u8>> };
( -> Result ) => { CbFn<io::Result<()>> };
}

macro_rules! call_cbfn {
( $cb:ident, $rv:expr, ) => { let x: () = $rv; $cb.call(x); };
( $cb:ident, $rv:expr, -> ! ) => { let _: ! = $rv; };
( $cb:ident, $rv:expr, -> u64 ) => { let x: u64 = $rv; $cb.call(x); };
( $cb:ident, $rv:expr, -> $t:ty ) => { let x: $t = $rv; $cb.call(x.from_sgx_result()); };
( $cb:ident, $rv:expr, ) => { let x: () = $rv; $cb.call(x); };
( $cb:ident, $rv:expr, -> ! ) => { let _: ! = $rv; };
( $cb:ident, $rv:expr, -> u64 ) => { let x: u64 = $rv; $cb.call(x); };
( $cb:ident, $rv:expr, -> (u64, *const InsecureTimeInfo) ) => { let x: (u64, *const InsecureTimeInfo) = $rv; $cb.call(x); };
( $cb:ident, $rv:expr, -> $t:ty ) => { let x: $t = $rv; $cb.call(x.from_sgx_result()); };
}

macro_rules! define_callback {
Expand Down
12 changes: 7 additions & 5 deletions intel-sgx/async-usercalls/src/provider_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::io_bufs::UserBuf;
use crate::raw::RawApi;
use crate::utils::MakeSend;
use crate::{AsyncUsercallProvider, CancelHandle};
use fortanix_sgx_abi::Fd;
use fortanix_sgx_abi::{Fd, InsecureTimeInfo};
use std::io;
use std::mem::{self, ManuallyDrop};
use std::net::{TcpListener, TcpStream};
Expand Down Expand Up @@ -251,13 +251,15 @@ impl AsyncUsercallProvider {
/// callbacks.
pub fn insecure_time<F>(&self, callback: F)
where
F: FnOnce(SystemTime) + Send + 'static,
F: FnOnce(SystemTime, *const InsecureTimeInfo) + Send + 'static,
{
let cb = move |nanos_since_epoch| {
let cb = move |(nanos_since_epoch, insecure_time_info_ptr): (u64, *const InsecureTimeInfo)| {
let t = UNIX_EPOCH + Duration::from_nanos(nanos_since_epoch);
callback(t);
callback(t, insecure_time_info_ptr);
};
unsafe {
// TODO We could detect if we're able to handle insecure time within the enclave, and
// avoid the async call
self.raw_insecure_time(Some(cb.into()));
}
}
Expand Down Expand Up @@ -285,4 +287,4 @@ fn copy_user_buffer(buf: &UserRef<ByteBuffer>) -> Vec<u8> {
Vec::new()
}
}
}
}
8 changes: 4 additions & 4 deletions intel-sgx/async-usercalls/src/raw.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::callback::*;
use crate::{AsyncUsercallProvider, CancelHandle};
use fortanix_sgx_abi::Fd;
use fortanix_sgx_abi::{Fd, InsecureTimeInfo};
use std::io;
use std::os::fortanix_sgx::usercalls::raw::ByteBuffer;
use std::os::fortanix_sgx::usercalls::raw::{Usercall, UsercallNrs};
Expand Down Expand Up @@ -51,7 +51,7 @@ pub trait RawApi {
callback: Option<CbFn<io::Result<Fd>>>,
) -> CancelHandle;

unsafe fn raw_insecure_time(&self, callback: Option<CbFn<u64>>);
unsafe fn raw_insecure_time(&self, callback: Option<CbFn<(u64, *const InsecureTimeInfo)>>);

unsafe fn raw_alloc(&self, size: usize, alignment: usize, callback: Option<CbFn<io::Result<*mut u8>>>);

Expand Down Expand Up @@ -137,7 +137,7 @@ impl RawApi for AsyncUsercallProvider {
self.send_usercall(u, callback.map(|cb| Callback::connect_stream(cb)))
}

unsafe fn raw_insecure_time(&self, callback: Option<CbFn<u64>>) {
unsafe fn raw_insecure_time(&self, callback: Option<CbFn<(u64, *const InsecureTimeInfo)>>) {
let u = Usercall(UsercallNrs::insecure_time as _, 0, 0, 0, 0);
self.send_usercall(u, callback.map(|cb| Callback::insecure_time(cb)));
}
Expand Down Expand Up @@ -172,7 +172,7 @@ mod tests {
let (tx, rx) = mpmc::bounded(N);
for _ in 0..N {
let tx = tx.clone();
let cb = move |d| {
let cb = move |(d, _)| {
let system_time = UNIX_EPOCH + Duration::from_nanos(d);
tx.send(system_time).unwrap();
};
Expand Down
2 changes: 1 addition & 1 deletion intel-sgx/async-usercalls/src/test_support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl Drop for AutoPollingProvider {
fn drop(&mut self) {
self.shutdown.store(true, Ordering::Relaxed);
// send a usercall to ensure thread wakes up
self.provider.insecure_time(|_| {});
self.provider.insecure_time(|_, _| {});
self.join_handle.take().unwrap().join().unwrap();
}
}
3 changes: 2 additions & 1 deletion intel-sgx/enclave-runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ exclude = ["fake-vdso/.gitignore", "fake-vdso/Makefile", "fake-vdso/main.S"]
[dependencies]
# Project dependencies
sgxs = { version = "0.8.0", path = "../sgxs" }
fortanix-sgx-abi = { version = "0.5.0", path = "../fortanix-sgx-abi" }
fortanix-sgx-abi = { version = "0.6.0", path = "../fortanix-sgx-abi" }
sgx-isa = { version = "0.4.0", path = "../sgx-isa" }
insecure-time = { version = "0.1", path = "../insecure-time", features = ["estimate_crystal_clock_freq"] }
ipc-queue = { version = "0.3.0", path = "../../ipc-queue" }

# External dependencies
Expand Down
5 changes: 4 additions & 1 deletion intel-sgx/enclave-runner/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct Command {
size: usize,
usercall_ext: Option<Box<dyn UsercallExtension>>,
forward_panics: bool,
force_time_usercalls: bool,
cmd_args: Vec<Vec<u8>>,
}

Expand All @@ -44,6 +45,7 @@ impl Command {
size: usize,
usercall_ext: Option<Box<dyn UsercallExtension>>,
forward_panics: bool,
force_time_usercalls: bool,
cmd_args: Vec<Vec<u8>>,
) -> Command {
let main = tcss.remove(0);
Expand All @@ -54,6 +56,7 @@ impl Command {
size,
usercall_ext,
forward_panics,
force_time_usercalls,
cmd_args,
}
}
Expand All @@ -63,6 +66,6 @@ impl Command {
}

pub fn run(self) -> Result<(), Error> {
EnclaveState::main_entry(self.main, self.threads, self.usercall_ext, self.forward_panics, self.cmd_args)
EnclaveState::main_entry(self.main, self.threads, self.usercall_ext, self.forward_panics, self.force_time_usercalls, self.cmd_args)
}
}
3 changes: 2 additions & 1 deletion intel-sgx/enclave-runner/src/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ impl Library {
size: usize,
usercall_ext: Option<Box<dyn UsercallExtension>>,
forward_panics: bool,
force_time_usercalls: bool,
) -> Library {
Library {
enclave: EnclaveState::library(tcss, usercall_ext, forward_panics),
enclave: EnclaveState::library(tcss, usercall_ext, forward_panics, force_time_usercalls),
address,
size,
}
Expand Down
20 changes: 17 additions & 3 deletions intel-sgx/enclave-runner/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pub struct EnclaveBuilder<'a> {
load_and_sign: Option<Box<dyn FnOnce(Signer) -> Result<Sigstruct, anyhow::Error>>>,
hash_enclave: Option<Box<dyn FnOnce(&mut EnclaveSource<'_>) -> Result<EnclaveHash, anyhow::Error>>>,
forward_panics: bool,
force_time_usercalls: bool,
cmd_args: Option<Vec<Vec<u8>>>,
}

Expand Down Expand Up @@ -145,6 +146,7 @@ impl<'a> EnclaveBuilder<'a> {
load_and_sign: None,
hash_enclave: None,
forward_panics: false,
force_time_usercalls: true, // By default, keep the old behavior of always doing a usercall on an insecure_time call
cmd_args: None,
};

Expand Down Expand Up @@ -266,6 +268,16 @@ impl<'a> EnclaveBuilder<'a> {
self
}

/// SGXv2 platforms allow enclaves to use the `rdtsc` instruction. This can speed up
/// performance significantly as enclave no longer need to call out to userspace to request the
/// current time. Unfortunately, older enclaves are not compatible with new enclave runners.
/// Also, sometimes the behavior of enclaves always calling out the userspace needs to be
/// simulated. This setting enforces the old behavior.
pub fn force_insecure_time_usercalls(&mut self, force_time_usercalls: bool) -> &mut Self {
self.force_time_usercalls = force_time_usercalls;
self
}

fn initialized_args_mut(&mut self) -> &mut Vec<Vec<u8>> {
self.cmd_args.get_or_insert_with(|| vec![b"enclave".to_vec()])
}
Expand Down Expand Up @@ -309,7 +321,7 @@ impl<'a> EnclaveBuilder<'a> {
fn load<T: Load>(
mut self,
loader: &mut T,
) -> Result<(Vec<ErasedTcs>, *mut c_void, usize, bool), anyhow::Error> {
) -> Result<(Vec<ErasedTcs>, *mut c_void, usize, bool, bool), anyhow::Error> {
let signature = match self.signature {
Some(sig) => sig,
None => self
Expand All @@ -320,6 +332,7 @@ impl<'a> EnclaveBuilder<'a> {
let miscselect = self.miscselect.unwrap_or(signature.miscselect);
let mapping = loader.load(&mut self.enclave, &signature, attributes, miscselect)?;
let forward_panics = self.forward_panics;
let force_time_usercalls = self.force_time_usercalls;
if mapping.tcss.is_empty() {
unimplemented!()
}
Expand All @@ -328,6 +341,7 @@ impl<'a> EnclaveBuilder<'a> {
mapping.info.address(),
mapping.info.size(),
forward_panics,
force_time_usercalls,
))
}

Expand All @@ -336,7 +350,7 @@ impl<'a> EnclaveBuilder<'a> {
let args = self.cmd_args.take().unwrap_or_default();
let c = self.usercall_ext.take();
self.load(loader)
.map(|(t, a, s, fp)| Command::internal_new(t, a, s, c, fp, args))
.map(|(t, a, s, fp, dti)| Command::internal_new(t, a, s, c, fp, dti, args))
}

/// Panics if you have previously called [`arg`] or [`args`].
Expand All @@ -349,6 +363,6 @@ impl<'a> EnclaveBuilder<'a> {
}
let c = self.usercall_ext.take();
self.load(loader)
.map(|(t, a, s, fp)| Library::internal_new(t, a, s, c, fp))
.map(|(t, a, s, fp, dti)| Library::internal_new(t, a, s, c, fp, dti))
}
}
2 changes: 1 addition & 1 deletion intel-sgx/enclave-runner/src/usercalls/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl<'future, 'ioinput: 'future, 'tcs: 'ioinput> Usercalls<'future> for Handler<

fn insecure_time(
self,
) -> std::pin::Pin<Box<dyn Future<Output = (Self, UsercallResult<u64>)> + 'future>> {
) -> std::pin::Pin<Box<dyn Future<Output = (Self, UsercallResult<(u64, *const InsecureTimeInfo)>)> + 'future>> {
async move {
let ret = Ok(self.0.insecure_time());
return (self, ret);
Expand Down
Loading