Skip to content

Commit fb97c07

Browse files
author
Jethro Beekman
committed
SGX target: implement user memory management
1 parent 87645db commit fb97c07

File tree

5 files changed

+411
-3
lines changed

5 files changed

+411
-3
lines changed

src/libstd/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@
310310
#![feature(panic_info_message)]
311311
#![feature(non_exhaustive)]
312312
#![feature(alloc_layout_extra)]
313-
#![cfg_attr(target_env = "sgx", feature(global_asm, range_contains))]
313+
#![cfg_attr(target_env = "sgx", feature(global_asm, range_contains, slice_index_methods, decl_macro, coerce_unsized))]
314314

315315
#![default_lib_allocator]
316316

src/libstd/sys/sgx/abi/mem.rs

+16
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ pub unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T {
2020
(image_base()+offset) as *mut T
2121
}
2222

23+
extern {
24+
static ENCLAVE_SIZE: usize;
25+
}
26+
2327
// Do not remove inline: will result in relocation failure
2428
// For the same reason we use inline ASM here instead of an extern static to
2529
// locate the base
@@ -29,3 +33,15 @@ fn image_base() -> u64 {
2933
unsafe{asm!("lea IMAGE_BASE(%rip),$0":"=r"(base))};
3034
base
3135
}
36+
37+
pub fn is_enclave_range(p: *const u8, len: usize) -> bool {
38+
let start=p as u64;
39+
let end=start+(len as u64);
40+
start >= image_base() && end <= image_base()+(unsafe{ENCLAVE_SIZE} as u64) // unsafe ok: link-time constant
41+
}
42+
43+
pub fn is_user_range(p: *const u8, len: usize) -> bool {
44+
let start=p as u64;
45+
let end=start+(len as u64);
46+
end <= image_base() || start >= image_base()+(unsafe{ENCLAVE_SIZE} as u64) // unsafe ok: link-time constant
47+
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ pub(super) fn exit_with_code(code: isize) -> ! {
100100
let _ = write!(out, "Exited with status code {}", code);
101101
}
102102
}
103-
unsafe { usercalls::raw::exit(code != 0) };
103+
usercalls::exit(code != 0);
104104
}
105105

106106
#[unstable(feature = "perma_unstable", issue = "0")]
+319
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(unused)]
12+
13+
use ptr;
14+
use mem;
15+
use cell::UnsafeCell;
16+
use slice;
17+
use ops::{Deref, DerefMut, Index, IndexMut, CoerceUnsized};
18+
use slice::SliceIndex;
19+
20+
use fortanix_sgx_abi::*;
21+
use super::super::mem::is_user_range;
22+
23+
/// A type that can be safely read from userspace. Most types that don't have a
24+
/// destructor and don't contain enums or references or Rust-style owned
25+
/// pointers (Vec, Arc, etc.) should be ok. Also they shouldn't contain any
26+
/// internal padding.
27+
pub unsafe trait UserSafeSized: Sized {}
28+
29+
unsafe impl UserSafeSized for u8 {}
30+
unsafe impl<T> UserSafeSized for FifoDescriptor<T> {}
31+
unsafe impl UserSafeSized for ByteBuffer {}
32+
unsafe impl UserSafeSized for Usercall {}
33+
unsafe impl UserSafeSized for Return {}
34+
unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {}
35+
36+
/// A type that can be represented in memory as one or more `UserSafeSized`s.
37+
pub unsafe trait UserSafe {
38+
unsafe fn align_of() -> usize;
39+
40+
unsafe fn from_raw_parts_unchecked(ptr: *const u8, size: usize) -> *const Self;
41+
42+
unsafe fn from_raw_parts(ptr: *const u8, size: usize) -> *const Self {
43+
let ret = Self::from_raw_parts_unchecked(ptr, size);
44+
Self::check_ptr(ret);
45+
ret
46+
}
47+
48+
unsafe fn check_ptr(ptr: *const Self) {
49+
let is_aligned = |p| -> bool {
50+
0 == (p as usize) & (Self::align_of() - 1)
51+
};
52+
53+
assert!(is_aligned(ptr as *const u8));
54+
assert!(is_user_range(ptr as _, mem::size_of_val(&*ptr)));
55+
assert!(!ptr.is_null());
56+
}
57+
}
58+
59+
unsafe impl<T: UserSafeSized> UserSafe for T {
60+
unsafe fn align_of() -> usize {
61+
mem::align_of::<T>()
62+
}
63+
64+
unsafe fn from_raw_parts_unchecked(ptr: *const u8, size: usize) -> *const Self {
65+
assert_eq!(size, mem::size_of::<T>());
66+
ptr as _
67+
}
68+
}
69+
70+
unsafe impl<T: UserSafeSized> UserSafe for [T] {
71+
unsafe fn align_of() -> usize {
72+
mem::align_of::<T>()
73+
}
74+
75+
unsafe fn from_raw_parts_unchecked(ptr: *const u8, size: usize) -> *const Self {
76+
let elem_size = mem::size_of::<T>();
77+
assert_eq!(size % elem_size, 0);
78+
let len = size / elem_size;
79+
slice::from_raw_parts(ptr as _, len)
80+
}
81+
}
82+
83+
/// A reference to some type in userspace memory. `&UserRef<T>` is equivalent
84+
/// to `&T` in enclave memory. Access to the memory is only allowed by copying
85+
/// to avoid TOCTTOU issues. After copying, code should make sure to completely
86+
/// check the value before use.
87+
pub struct UserRef<T: ?Sized>(UnsafeCell<T>);
88+
/// An owned type in userspace memory. `User<T>` is equivalent to `Box<T>` in
89+
/// enclave memory. Access to the memory is only allowed by copying to avoid
90+
/// TOCTTOU issues. The user memory will be freed when the value is dropped.
91+
/// After copying, code should make sure to completely check the value before
92+
/// use.
93+
pub struct User<T: UserSafe + ?Sized>(*mut UserRef<T>);
94+
95+
impl<T: ?Sized> User<T> where T: UserSafe {
96+
fn new_uninit_bytes(size: usize) -> Self {
97+
unsafe {
98+
let ptr = super::alloc(size, T::align_of()).expect("User memory allocation failed");
99+
User(T::from_raw_parts(ptr as _, size) as _)
100+
}
101+
}
102+
103+
pub fn new_from_enclave(val: &T) -> Self {
104+
unsafe {
105+
let ret = Self::new_uninit_bytes(mem::size_of_val(val));
106+
ptr::copy(val as *const T as *const u8, ret.0 as *mut T as *mut u8, mem::size_of_val(val));
107+
ret
108+
}
109+
}
110+
111+
/// Create an owned `User<T>` from a raw pointer. The pointer should be
112+
/// freeable with the `free` usercall and the alignment of `T`.
113+
///
114+
/// # Panics
115+
/// This function panics if:
116+
///
117+
/// * The pointer is not aligned
118+
/// * The pointer is null
119+
/// * The pointed-to range is not in user memory
120+
pub unsafe fn from_raw(ptr: *mut T) -> Self {
121+
T::check_ptr(ptr);
122+
User(ptr as _)
123+
}
124+
125+
/// Convert this value into a raw pointer. The value will no longer be
126+
/// automatically freed.
127+
pub fn into_raw(self) -> *mut T {
128+
let ret = self.0;
129+
mem::forget(self);
130+
ret as _
131+
}
132+
}
133+
134+
impl<T> User<T> where T: UserSafe {
135+
pub fn uninitialized() -> Self {
136+
Self::new_uninit_bytes(mem::size_of::<T>())
137+
}
138+
}
139+
140+
impl<T> User<[T]> where [T]: UserSafe {
141+
pub fn uninitialized(n: usize) -> Self {
142+
Self::new_uninit_bytes(n * mem::size_of::<T>())
143+
}
144+
145+
/// Create an owned `User<[T]>` from a raw thin pointer and a slice length.
146+
/// The pointer should be freeable with the `free` usercall and the
147+
/// alignment of `T`.
148+
///
149+
/// # Panics
150+
/// This function panics if:
151+
///
152+
/// * The pointer is not aligned
153+
/// * The pointer is null
154+
/// * The pointed-to range is not in user memory
155+
pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
156+
User(<[T]>::from_raw_parts(ptr as _, len) as _)
157+
}
158+
}
159+
160+
impl<T: ?Sized> UserRef<T> where T: UserSafe {
161+
/// Create a `&UserRef<[T]>` from a raw pointer.
162+
///
163+
/// # Panics
164+
/// This function panics if:
165+
///
166+
/// * The pointer is not aligned
167+
/// * The pointer is null
168+
/// * The pointed-to range is not in user memory
169+
pub unsafe fn from_ptr<'a>(ptr: *const T) -> &'a Self {
170+
T::check_ptr(ptr);
171+
&*(ptr as *const Self)
172+
}
173+
174+
/// Create a `&mut UserRef<[T]>` from a raw pointer.
175+
///
176+
/// # Panics
177+
/// This function panics if:
178+
///
179+
/// * The pointer is not aligned
180+
/// * The pointer is null
181+
/// * The pointed-to range is not in user memory
182+
pub unsafe fn from_mut_ptr<'a>(ptr: *mut T) -> &'a mut Self {
183+
T::check_ptr(ptr);
184+
&mut*(ptr as *mut Self)
185+
}
186+
187+
/// # Panics
188+
/// This function panics if the destination doesn't have the same size as
189+
/// the source. This can happen for dynamically-sized types such as slices.
190+
pub fn copy_from_enclave(&mut self, val: &T) {
191+
unsafe {
192+
assert_eq!(mem::size_of_val(val), mem::size_of_val( &*self.0.get() ));
193+
ptr::copy(val as *const T as *const u8, self.0.get() as *mut T as *mut u8, mem::size_of_val(val));
194+
}
195+
}
196+
197+
/// # Panics
198+
/// This function panics if the destination doesn't have the same size as
199+
/// the source. This can happen for dynamically-sized types such as slices.
200+
pub fn copy_to_enclave(&self, dest: &mut T) {
201+
unsafe {
202+
assert_eq!(mem::size_of_val(dest), mem::size_of_val( &*self.0.get() ));
203+
ptr::copy(self.0.get() as *const T as *const u8, dest as *mut T as *mut u8, mem::size_of_val(dest));
204+
}
205+
}
206+
207+
pub fn as_raw_ptr(&self) -> *const T {
208+
self as *const _ as _
209+
}
210+
211+
pub fn as_raw_mut_ptr(&mut self) -> *mut T {
212+
self as *mut _ as _
213+
}
214+
}
215+
216+
impl<T> UserRef<T> where T: UserSafe {
217+
pub fn to_enclave(&self) -> T {
218+
unsafe { ptr::read(self.0.get()) }
219+
}
220+
}
221+
222+
impl<T> UserRef<[T]> where [T]: UserSafe {
223+
/// Create a `&UserRef<[T]>` from a raw thin pointer and a slice length.
224+
///
225+
/// # Panics
226+
/// This function panics if:
227+
///
228+
/// * The pointer is not aligned
229+
/// * The pointer is null
230+
/// * The pointed-to range is not in user memory
231+
pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
232+
&*(<[T]>::from_raw_parts(ptr as _, len * mem::size_of::<T>()) as *const Self)
233+
}
234+
235+
/// Create a `&mut UserRef<[T]>` from a raw thin pointer and a slice length.
236+
///
237+
/// # Panics
238+
/// This function panics if:
239+
///
240+
/// * The pointer is not aligned
241+
/// * The pointer is null
242+
/// * The pointed-to range is not in user memory
243+
pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self {
244+
&mut*(<[T]>::from_raw_parts(ptr as _, len * mem::size_of::<T>()) as *mut Self)
245+
}
246+
247+
pub fn as_ptr(&self) -> *const T {
248+
self.0.get() as _
249+
}
250+
251+
pub fn as_mut_ptr(&mut self) -> *mut T {
252+
self.0.get() as _
253+
}
254+
255+
pub fn len(&self) -> usize {
256+
unsafe { (*self.0.get()).len() }
257+
}
258+
259+
pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) {
260+
unsafe {
261+
if let Some(missing) = self.len().checked_sub(dest.capacity()) {
262+
dest.reserve(missing)
263+
}
264+
dest.set_len(self.len());
265+
self.copy_to_enclave(&mut dest[..]);
266+
}
267+
}
268+
269+
pub fn to_enclave(&self) -> Vec<T> {
270+
let mut ret = Vec::with_capacity(self.len());
271+
self.copy_to_enclave_vec(&mut ret);
272+
ret
273+
}
274+
}
275+
276+
impl<T: ?Sized> Deref for User<T> where T: UserSafe {
277+
type Target = UserRef<T>;
278+
279+
fn deref(&self) -> &Self::Target {
280+
unsafe { &*self.0 }
281+
}
282+
}
283+
284+
impl<T: ?Sized> DerefMut for User<T> where T: UserSafe {
285+
fn deref_mut(&mut self) -> &mut Self::Target {
286+
unsafe { &mut*self.0 }
287+
}
288+
}
289+
290+
impl<T: ?Sized> Drop for User<T> where T: UserSafe {
291+
fn drop(&mut self) {
292+
unsafe {
293+
let ptr = (*self.0).0.get();
294+
super::free(ptr as _, mem::size_of_val(&mut*ptr), T::align_of());
295+
}
296+
}
297+
}
298+
299+
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UserRef<U>> for UserRef<T> {}
300+
301+
impl<T, I: SliceIndex<[T]>> Index<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
302+
type Output = UserRef<I::Output>;
303+
304+
#[inline]
305+
fn index(&self, index: I) -> &UserRef<I::Output> {
306+
unsafe {
307+
UserRef::from_ptr(index.index(&*self.as_raw_ptr()))
308+
}
309+
}
310+
}
311+
312+
impl<T, I: SliceIndex<[T]>> IndexMut<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
313+
#[inline]
314+
fn index_mut(&mut self, index: I) -> &mut UserRef<I::Output> {
315+
unsafe {
316+
UserRef::from_mut_ptr(index.index_mut(&mut*self.as_raw_mut_ptr()))
317+
}
318+
}
319+
}

0 commit comments

Comments
 (0)