Skip to content

Commit 6423e43

Browse files
authored
Rollup merge of rust-lang#73269 - mzohreva:mz/sgx-wait-timeout, r=jethrogb
Enable some timeouts in SGX platform This would partially resolve fortanix/rust-sgx#31 cc @jethrogb and @Goirad
2 parents 7b66afd + 85c25ae commit 6423e43

File tree

13 files changed

+215
-48
lines changed

13 files changed

+215
-48
lines changed

src/libstd/sync/condvar.rs

-4
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,6 @@ mod tests {
694694

695695
#[test]
696696
#[cfg_attr(target_os = "emscripten", ignore)]
697-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
698697
fn wait_timeout_wait() {
699698
let m = Arc::new(Mutex::new(()));
700699
let c = Arc::new(Condvar::new());
@@ -714,7 +713,6 @@ mod tests {
714713

715714
#[test]
716715
#[cfg_attr(target_os = "emscripten", ignore)]
717-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
718716
fn wait_timeout_while_wait() {
719717
let m = Arc::new(Mutex::new(()));
720718
let c = Arc::new(Condvar::new());
@@ -739,7 +737,6 @@ mod tests {
739737

740738
#[test]
741739
#[cfg_attr(target_os = "emscripten", ignore)]
742-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
743740
fn wait_timeout_while_wake() {
744741
let pair = Arc::new((Mutex::new(false), Condvar::new()));
745742
let pair_copy = pair.clone();
@@ -763,7 +760,6 @@ mod tests {
763760

764761
#[test]
765762
#[cfg_attr(target_os = "emscripten", ignore)]
766-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
767763
fn wait_timeout_wake() {
768764
let m = Arc::new(Mutex::new(()));
769765
let c = Arc::new(Condvar::new());

src/libstd/sync/mpsc/mod.rs

-9
Original file line numberDiff line numberDiff line change
@@ -2088,7 +2088,6 @@ mod tests {
20882088
}
20892089

20902090
#[test]
2091-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
20922091
fn oneshot_single_thread_recv_timeout() {
20932092
let (tx, rx) = channel();
20942093
tx.send(()).unwrap();
@@ -2099,7 +2098,6 @@ mod tests {
20992098
}
21002099

21012100
#[test]
2102-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
21032101
fn stress_recv_timeout_two_threads() {
21042102
let (tx, rx) = channel();
21052103
let stress = stress_factor() + 100;
@@ -2130,7 +2128,6 @@ mod tests {
21302128
}
21312129

21322130
#[test]
2133-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
21342131
fn recv_timeout_upgrade() {
21352132
let (tx, rx) = channel::<()>();
21362133
let timeout = Duration::from_millis(1);
@@ -2142,7 +2139,6 @@ mod tests {
21422139
}
21432140

21442141
#[test]
2145-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
21462142
fn stress_recv_timeout_shared() {
21472143
let (tx, rx) = channel();
21482144
let stress = stress_factor() + 100;
@@ -2173,7 +2169,6 @@ mod tests {
21732169
}
21742170

21752171
#[test]
2176-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
21772172
fn very_long_recv_timeout_wont_panic() {
21782173
let (tx, rx) = channel::<()>();
21792174
let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX)));
@@ -2195,7 +2190,6 @@ mod tests {
21952190
}
21962191

21972192
#[test]
2198-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
21992193
fn shared_recv_timeout() {
22002194
let (tx, rx) = channel();
22012195
let total = 5;
@@ -2425,7 +2419,6 @@ mod sync_tests {
24252419
}
24262420

24272421
#[test]
2428-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
24292422
fn recv_timeout() {
24302423
let (tx, rx) = sync_channel::<i32>(1);
24312424
assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
@@ -2517,7 +2510,6 @@ mod sync_tests {
25172510
}
25182511

25192512
#[test]
2520-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
25212513
fn stress_recv_timeout_two_threads() {
25222514
let (tx, rx) = sync_channel::<i32>(0);
25232515

@@ -2543,7 +2535,6 @@ mod sync_tests {
25432535
}
25442536

25452537
#[test]
2546-
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
25472538
fn stress_recv_timeout_shared() {
25482539
const AMT: u32 = 1000;
25492540
const NTHREADS: u32 = 8;

src/libstd/sys/sgx/abi/usercalls/mod.rs

+89-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::cmp;
2-
use crate::io::{Error as IoError, IoSlice, IoSliceMut, Result as IoResult};
3-
use crate::time::Duration;
2+
use crate::convert::TryFrom;
3+
use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult};
4+
use crate::sys::rand::rdrand64;
5+
use crate::time::{Duration, Instant};
46

57
pub(crate) mod alloc;
68
#[macro_use]
@@ -149,10 +151,94 @@ pub fn exit(panic: bool) -> ! {
149151

150152
/// Usercall `wait`. See the ABI documentation for more information.
151153
#[unstable(feature = "sgx_platform", issue = "56975")]
152-
pub fn wait(event_mask: u64, timeout: u64) -> IoResult<u64> {
154+
pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult<u64> {
155+
if timeout != WAIT_NO && timeout != WAIT_INDEFINITE {
156+
// We don't want people to rely on accuracy of timeouts to make
157+
// security decisions in an SGX enclave. That's why we add a random
158+
// amount not exceeding +/- 10% to the timeout value to discourage
159+
// people from relying on accuracy of timeouts while providing a way
160+
// to make things work in other cases. Note that in the SGX threat
161+
// model the enclave runner which is serving the wait usercall is not
162+
// trusted to ensure accurate timeouts.
163+
if let Ok(timeout_signed) = i64::try_from(timeout) {
164+
let tenth = timeout_signed / 10;
165+
let deviation = (rdrand64() as i64).checked_rem(tenth).unwrap_or(0);
166+
timeout = timeout_signed.saturating_add(deviation) as _;
167+
}
168+
}
153169
unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
154170
}
155171

172+
/// This function makes an effort to wait for a non-spurious event at least as
173+
/// long as `duration`. Note that in general there is no guarantee about accuracy
174+
/// of time and timeouts in SGX model. The enclave runner serving usercalls may
175+
/// lie about current time and/or ignore timeout values.
176+
///
177+
/// Once the event is observed, `should_wake_up` will be used to determine
178+
/// whether or not the event was spurious.
179+
#[unstable(feature = "sgx_platform", issue = "56975")]
180+
pub fn wait_timeout<F>(event_mask: u64, duration: Duration, should_wake_up: F)
181+
where
182+
F: Fn() -> bool,
183+
{
184+
// Calls the wait usercall and checks the result. Returns true if event was
185+
// returned, and false if WouldBlock/TimedOut was returned.
186+
// If duration is None, it will use WAIT_NO.
187+
fn wait_checked(event_mask: u64, duration: Option<Duration>) -> bool {
188+
let timeout = duration.map_or(raw::WAIT_NO, |duration| {
189+
cmp::min((u64::MAX - 1) as u128, duration.as_nanos()) as u64
190+
});
191+
match wait(event_mask, timeout) {
192+
Ok(eventset) => {
193+
if event_mask == 0 {
194+
rtabort!("expected wait() to return Err, found Ok.");
195+
}
196+
rtassert!(eventset != 0 && eventset & !event_mask == 0);
197+
true
198+
}
199+
Err(e) => {
200+
rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock);
201+
false
202+
}
203+
}
204+
}
205+
206+
match wait_checked(event_mask, Some(duration)) {
207+
false => return, // timed out
208+
true if should_wake_up() => return, // woken up
209+
true => {} // spurious event
210+
}
211+
212+
// Drain all cached events.
213+
// Note that `event_mask != 0` is implied if we get here.
214+
loop {
215+
match wait_checked(event_mask, None) {
216+
false => break, // no more cached events
217+
true if should_wake_up() => return, // woken up
218+
true => {} // spurious event
219+
}
220+
}
221+
222+
// Continue waiting, but take note of time spent waiting so we don't wait
223+
// forever. We intentionally don't call `Instant::now()` before this point
224+
// to avoid the cost of the `insecure_time` usercall in case there are no
225+
// spurious wakeups.
226+
227+
let start = Instant::now();
228+
let mut remaining = duration;
229+
loop {
230+
match wait_checked(event_mask, Some(remaining)) {
231+
false => return, // timed out
232+
true if should_wake_up() => return, // woken up
233+
true => {} // spurious event
234+
}
235+
remaining = match duration.checked_sub(start.elapsed()) {
236+
Some(remaining) => remaining,
237+
None => break,
238+
}
239+
}
240+
}
241+
156242
/// Usercall `send`. See the ABI documentation for more information.
157243
#[unstable(feature = "sgx_platform", issue = "56975")]
158244
pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {

src/libstd/sys/sgx/condvar.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ impl Condvar {
3131
mutex.lock()
3232
}
3333

34-
pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
35-
rtabort!("timeout not supported in SGX");
34+
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
35+
let success = WaitQueue::wait_timeout(&self.inner, dur, || mutex.unlock());
36+
mutex.lock();
37+
success
3638
}
3739

3840
#[inline]

src/libstd/sys/sgx/mod.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ pub extern "C" fn __rust_abort() {
137137
abort_internal();
138138
}
139139

140-
pub fn hashmap_random_keys() -> (u64, u64) {
141-
fn rdrand64() -> u64 {
140+
pub mod rand {
141+
pub fn rdrand64() -> u64 {
142142
unsafe {
143143
let mut ret: u64 = 0;
144144
for _ in 0..10 {
@@ -149,7 +149,10 @@ pub fn hashmap_random_keys() -> (u64, u64) {
149149
rtabort!("Failed to obtain random data");
150150
}
151151
}
152-
(rdrand64(), rdrand64())
152+
}
153+
154+
pub fn hashmap_random_keys() -> (u64, u64) {
155+
(self::rand::rdrand64(), self::rand::rdrand64())
153156
}
154157

155158
pub use crate::sys_common::{AsInner, FromInner, IntoInner};

src/libstd/sys/sgx/thread.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ impl Thread {
7373
// FIXME: could store this pointer in TLS somewhere
7474
}
7575

76-
pub fn sleep(_dur: Duration) {
77-
rtabort!("can't sleep"); // FIXME
76+
pub fn sleep(dur: Duration) {
77+
usercalls::wait_timeout(0, dur, || true);
7878
}
7979

8080
pub fn join(self) {

0 commit comments

Comments
 (0)