Skip to content

Commit 2394fe3

Browse files
author
Vasili Novikov
committed
Async usercalls code review
1 parent 5703f54 commit 2394fe3

File tree

8 files changed

+37
-17
lines changed

8 files changed

+37
-17
lines changed

Diff for: .travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ matrix:
4545
- rustup target add x86_64-fortanix-unknown-sgx --toolchain nightly
4646
script:
4747
- cargo test --verbose --locked --all --exclude sgxs-loaders --exclude async-usercalls && [ "$(echo $(nm -D target/debug/sgx-detect|grep __vdso_sgx_enter_enclave))" = "w __vdso_sgx_enter_enclave" ]
48-
- CARGO_BUILD_RUSTFLAGS='-D warnings' cargo ci-test
48+
- cargo test --verbose --locked -p async-usercalls --target x86_64-fortanix-unknown-sgx --no-run
4949
- cargo test --verbose --locked -p dcap-ql --features link
5050
- cargo test --verbose --locked -p dcap-ql --features verify
5151
- cargo test --verbose --locked -p ias --features mbedtls

Diff for: intel-sgx/async-usercalls/.cargo/config.toml

-2
This file was deleted.

Diff for: intel-sgx/async-usercalls/src/io_bufs.rs

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ use std::ops::{Deref, DerefMut, Range};
55
use std::os::fortanix_sgx::usercalls::alloc::{User, UserRef};
66
use std::sync::Arc;
77

8+
/// Userspace buffer. Note that you have to be careful with reading data and writing data
9+
/// from the SGX enclave to/from userspace, to avoid stale memory data attacks.
10+
/// Using `UserRef<[u8]>` to access the data is a safe choice, as it handles the nuances internally.
811
pub struct UserBuf(UserBufKind);
912

1013
enum UserBufKind {

Diff for: intel-sgx/async-usercalls/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// deny compilation warnings for the whole `async-usercalls` module
2+
#![deny(warnings)]
3+
14
//! This crate provides an interface for performing asynchronous usercalls in
25
//! SGX enclaves. The motivation behind asynchronous usercalls and ABI
36
//! documentation can be found

Diff for: intel-sgx/async-usercalls/src/provider_api.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ impl AsyncUsercallProvider {
2828
let ptr = read_buf.as_mut_ptr();
2929
let len = read_buf.len();
3030
let cb = move |res: io::Result<usize>| {
31+
// Passing a `User<u8>` likely leads to the value being dropped implicitly,
32+
// which will cause a synchronous `free` usercall.
33+
// See: https://github.com/fortanix/rust-sgx/issues/531
3134
let read_buf = ManuallyDrop::into_inner(read_buf).into_inner();
3235
callback(res, read_buf);
3336
};
@@ -93,6 +96,8 @@ impl AsyncUsercallProvider {
9396
where
9497
F: FnOnce(io::Result<TcpListener>) + Send + 'static,
9598
{
99+
// `User::<[u8]>::uninitialized` causes a synchronous usercall when dropped.
100+
// See: https://github.com/fortanix/rust-sgx/issues/531
96101
let mut addr_buf = ManuallyDrop::new(MakeSend::new(User::<[u8]>::uninitialized(addr.len())));
97102
let mut local_addr_buf = ManuallyDrop::new(MakeSend::new(User::<ByteBuffer>::uninitialized()));
98103

@@ -101,7 +106,12 @@ impl AsyncUsercallProvider {
101106
let local_addr_ptr = local_addr_buf.as_raw_mut_ptr();
102107

103108
let cb = move |res: io::Result<Fd>| {
109+
// `_addr_buf` is of type `MakeSend<_>`, which will lead to a synchronous usercall
110+
// upon being dropped.
111+
// See: https://github.com/fortanix/rust-sgx/issues/531
104112
let _addr_buf = ManuallyDrop::into_inner(addr_buf);
113+
// Same as above, synchronous usercall will happen upon dropping
114+
// See: https://github.com/fortanix/rust-sgx/issues/531
105115
let local_addr_buf = ManuallyDrop::into_inner(local_addr_buf);
106116

107117
let local_addr = Some(string_from_bytebuffer(&local_addr_buf, "bind_stream", "local_addr"));
@@ -253,12 +263,15 @@ impl AsyncUsercallProvider {
253263
}
254264
}
255265

266+
// The code is similar to `rust-lang/sys/sgx/abi/usercalls/mod.rs`,
267+
// see: https://github.com/fortanix/rust-sgx/issues/532
256268
fn string_from_bytebuffer(buf: &UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
257269
String::from_utf8(copy_user_buffer(buf))
258270
.unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
259271
}
260272

261-
// adapted from libstd sys/sgx/abi/usercalls/alloc.rs
273+
// The code is similar to `rust-lang/sys/sgx/abi/usercalls/mod.rs`,
274+
// see: https://github.com/fortanix/rust-sgx/issues/532
262275
fn copy_user_buffer(buf: &UserRef<ByteBuffer>) -> Vec<u8> {
263276
unsafe {
264277
let buf = buf.to_enclave();

Diff for: intel-sgx/async-usercalls/src/queues.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ fn init_async_queues() -> io::Result<(Sender<Usercall>, Sender<Cancel>, Receiver
7272

7373
// FIXME: once `WithId` is exported from `std::os::fortanix_sgx::usercalls::raw`, we can remove
7474
// `transmute` calls here and use FifoDescriptor/WithId from std everywhere including in ipc-queue.
75+
// See: https://github.com/fortanix/rust-sgx/issues/533
7576
let utx = unsafe { Sender::from_descriptor(std::mem::transmute(usercall_queue), QueueSynchronizer { queue: Queue::Usercall }) };
7677
let ctx = unsafe { Sender::from_descriptor(std::mem::transmute(cancel_queue), QueueSynchronizer { queue: Queue::Cancel }) };
7778
let rx = unsafe { Receiver::from_descriptor(std::mem::transmute(return_queue), QueueSynchronizer { queue: Queue::Return }) };
@@ -175,18 +176,24 @@ mod map {
175176

176177
/// Insert a new value and return the index.
177178
///
178-
/// If trying to insert more than `u32` keys, the insert operation will hang forever.
179+
/// # Panics
180+
/// Panics if `u32::MAX` entries are kept in the queue and a new one is attempted
181+
/// to be inserted. Note that removing entries from the queue also frees up space
182+
/// and the number of available entries.
179183
pub fn insert(&mut self, value: T) -> u32 {
184+
let initial_id = self.next_id;
180185
loop {
181186
let id = self.next_id;
182-
// We intentionally ignore the overflow, thus allowing `next_id` to jump back to 0
187+
// We intentionally ignore the overflow here, thus allowing `next_id` to jump back to 0
183188
// after `u32::MAX` number of insertions.
184189
self.next_id = self.next_id.overflowing_add(1).0;
185-
if self.map.contains_key(&id) {
186-
continue
187-
} else {
190+
if !self.map.contains_key(&id) {
188191
self.map.insert(id, value);
189192
return id
193+
} else if id == initial_id {
194+
panic!("Cannot keep more than {} entries into the async queue. Aborting.", u32::MAX)
195+
} else {
196+
continue
190197
}
191198
}
192199
}

Diff for: intel-sgx/async-usercalls/src/utils.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ use std::ops::{Deref, DerefMut};
22
use std::os::fortanix_sgx::usercalls::alloc::User;
33
use std::os::fortanix_sgx::usercalls::raw::ByteBuffer;
44

5+
// This might be removed in the future, see: https://github.com/fortanix/rust-sgx/issues/530
56
pub(crate) trait MakeSendMarker {}
67

8+
// This might be removed in the future, see: https://github.com/fortanix/rust-sgx/issues/530
79
pub(crate) struct MakeSend<T: MakeSendMarker>(T);
810

911
impl<T: MakeSendMarker> MakeSend<T> {

Diff for: ipc-queue/src/position.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,7 @@ impl<T> PositionMonitor<T> {
4141
pub fn read_position(&self) -> ReadPosition {
4242
let current = self.fifo.current_offsets(Ordering::Relaxed);
4343
let read_epoch = self.read_epoch.load(Ordering::Relaxed);
44-
let read_epoch_shifted = read_epoch
45-
.checked_shl(32)
46-
.expect("Read epoch is >= 2^32 (2 to the power of 32). This is unsupported.");
47-
ReadPosition(read_epoch_shifted | (current.read_offset() as u64))
44+
ReadPosition((read_epoch << 32) | (current.read_offset() as u64))
4845
}
4946

5047
pub fn write_position(&self) -> WritePosition {
@@ -58,10 +55,7 @@ impl<T> PositionMonitor<T> {
5855
if current.read_high_bit() != current.write_high_bit() {
5956
write_epoch += 1;
6057
}
61-
let write_epoch_shifted = write_epoch
62-
.checked_shl(32)
63-
.expect("Write epoch is >= 2^32 (2 to the power of 32). This is unsupported.");
64-
WritePosition(write_epoch_shifted | (current.write_offset() as u64))
58+
WritePosition((write_epoch << 32) | (current.write_offset() as u64))
6559
}
6660
}
6761

0 commit comments

Comments
 (0)