Skip to content

Commit

Permalink
Support letting enclaves do time keeping
Browse files Browse the repository at this point in the history
  • Loading branch information
raoulstrackx committed Dec 12, 2024
1 parent f3b05c8 commit a34e976
Show file tree
Hide file tree
Showing 15 changed files with 103 additions and 40 deletions.
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

0 comments on commit a34e976

Please sign in to comment.