]> git.lizzy.rs Git - rust.git/blobdiff - src/libstd/sys/sgx/abi/usercalls/alloc.rs
Add `std::os::fortanix_sgx` module
[rust.git] / src / libstd / sys / sgx / abi / usercalls / alloc.rs
index 64968a9970c487d0dc143b97fba1b9516bfc7ef6..f1689091eb593a9069feeebe036e59e64008fc94 100644 (file)
@@ -10,7 +10,7 @@
 
 #![allow(unused)]
 
-use ptr;
+use ptr::{self, NonNull};
 use mem;
 use cell::UnsafeCell;
 use slice;
 ///   as vtable pointers) must not be leaked for confidentiality reasons.
 ///
 /// Non-exhaustive list of specific requirements for reading from userspace:
-/// * Any bit pattern is valid for this type (no `enum`s). There can be no
+/// * **Any bit pattern is valid** for this type (no `enum`s). There can be no
 ///   guarantee that the value correctly adheres to the expectations of the
 ///   type, so any value must be valid for this type.
 ///
 /// Non-exhaustive list of specific requirements for writing to userspace:
-/// * No pointers to enclave memory. Memory addresses of data in enclave memory
-///   must not be leaked for confidentiality reasons.
-/// * No internal padding. Padding might contain previously-initialized secret
-///   data stored at that memory location and must not be leaked for
+/// * **No pointers to enclave memory.** Memory addresses of data in enclave
+///   memory must not be leaked for confidentiality reasons.
+/// * **No internal padding.** Padding might contain previously-initialized
+///   secret data stored at that memory location and must not be leaked for
 ///   confidentiality reasons.
+#[unstable(feature = "sgx_platform", issue = "56975")]
 pub unsafe trait UserSafeSized: Copy + Sized {}
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 unsafe impl UserSafeSized for u8 {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
 unsafe impl<T> UserSafeSized for FifoDescriptor<T> {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
 unsafe impl UserSafeSized for ByteBuffer {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
 unsafe impl UserSafeSized for Usercall {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
 unsafe impl UserSafeSized for Return {}
+#[unstable(feature = "sgx_platform", issue = "56975")]
 unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {}
 
 /// A type that can be represented in memory as one or more `UserSafeSized`s.
+#[unstable(feature = "sgx_platform", issue = "56975")]
 pub unsafe trait UserSafe {
-    unsafe fn align_of() -> usize;
+    /// Equivalent to `mem::align_of::<Self>`.
+    fn align_of() -> usize;
 
+    /// Construct a pointer to `Self` given a memory range in user space.
+    ///
     /// NB. This takes a size, not a length!
-    unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self;
+    ///
+    /// # Safety
+    /// The caller must ensure the memory range is in user memory, is the
+    /// correct size and is correctly aligned and points to the right type.
+    unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self;
 
+    /// Construct a pointer to `Self` given a memory range.
+    ///
     /// NB. This takes a size, not a length!
-    unsafe fn from_raw_sized(ptr: *const u8, size: usize) -> *const Self {
+    ///
+    /// # Safety
+    /// The caller must ensure the memory range points to the correct type.
+    ///
+    /// # Panics
+    /// This function panics if:
+    ///
+    /// * The pointer is not aligned
+    /// * The pointer is null
+    /// * The pointed-to range is not in user memory
+    unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> {
         let ret = Self::from_raw_sized_unchecked(ptr, size);
         Self::check_ptr(ret);
-        ret
+        NonNull::new_unchecked(ret as _)
     }
 
+    /// Check if a pointer may point to Self in user memory.
+    ///
+    /// # Safety
+    /// The caller must ensure the memory range points to the correct type and
+    /// length (if this is a slice).
+    ///
+    /// # Panics
+    /// This function panics if:
+    ///
+    /// * The pointer is not aligned
+    /// * The pointer is null
+    /// * The pointed-to range is not in user memory
     unsafe fn check_ptr(ptr: *const Self) {
         let is_aligned = |p| -> bool {
             0 == (p as usize) & (Self::align_of() - 1)
@@ -83,27 +122,29 @@ unsafe fn check_ptr(ptr: *const Self) {
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 unsafe impl<T: UserSafeSized> UserSafe for T {
-    unsafe fn align_of() -> usize {
+    fn align_of() -> usize {
         mem::align_of::<T>()
     }
 
-    unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self {
+    unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
         assert_eq!(size, mem::size_of::<T>());
         ptr as _
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 unsafe impl<T: UserSafeSized> UserSafe for [T] {
-    unsafe fn align_of() -> usize {
+    fn align_of() -> usize {
         mem::align_of::<T>()
     }
 
-    unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self {
+    unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
         let elem_size = mem::size_of::<T>();
         assert_eq!(size % elem_size, 0);
         let len = size / elem_size;
-        slice::from_raw_parts(ptr as _, len)
+        slice::from_raw_parts_mut(ptr as _, len)
     }
 }
 
@@ -111,14 +152,40 @@ unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self {
 /// to `&T` in enclave memory. Access to the memory is only allowed by copying
 /// to avoid TOCTTOU issues. After copying, code should make sure to completely
 /// check the value before use.
+///
+/// It is also possible to obtain a mutable reference `&mut UserRef<T>`. Unlike
+/// regular mutable references, these are not exclusive. Userspace may always
+/// write to the backing memory at any time, so it can't be assumed that there
+/// the pointed-to memory is uniquely borrowed. The two different refence types
+/// are used solely to indicate intent: a mutable reference is for writing to
+/// user memory, an immutable reference for reading from user memory.
+#[unstable(feature = "sgx_platform", issue = "56975")]
 pub struct UserRef<T: ?Sized>(UnsafeCell<T>);
 /// An owned type in userspace memory. `User<T>` is equivalent to `Box<T>` in
 /// enclave memory. Access to the memory is only allowed by copying to avoid
 /// TOCTTOU issues. The user memory will be freed when the value is dropped.
 /// After copying, code should make sure to completely check the value before
 /// use.
-pub struct User<T: UserSafe + ?Sized>(*mut UserRef<T>);
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct User<T: UserSafe + ?Sized>(NonNull<UserRef<T>>);
+
+trait NewUserRef<T: ?Sized> {
+    unsafe fn new_userref(v: T) -> Self;
+}
+
+impl<T: ?Sized> NewUserRef<*mut T> for NonNull<UserRef<T>> {
+    unsafe fn new_userref(v: *mut T) -> Self {
+        NonNull::new_unchecked(v as _)
+    }
+}
 
+impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> {
+    unsafe fn new_userref(v: NonNull<T>) -> Self {
+        NonNull::new_userref(v.as_ptr())
+    }
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T: ?Sized> User<T> where T: UserSafe {
     // This function returns memory that is practically uninitialized, but is
     // not considered "unspecified" or "undefined" for purposes of an
@@ -127,24 +194,28 @@ impl<T: ?Sized> User<T> where T: UserSafe {
     fn new_uninit_bytes(size: usize) -> Self {
         unsafe {
             let ptr = super::alloc(size, T::align_of()).expect("User memory allocation failed");
-            User(T::from_raw_sized(ptr as _, size) as _)
+            User(NonNull::new_userref(T::from_raw_sized(ptr as _, size)))
         }
     }
 
+    /// Copy `val` into freshly allocated space in user memory.
     pub fn new_from_enclave(val: &T) -> Self {
         unsafe {
             let ret = Self::new_uninit_bytes(mem::size_of_val(val));
             ptr::copy(
                 val as *const T as *const u8,
-                ret.0 as *mut T as *mut u8,
+                ret.0.as_ptr() as *mut u8,
                 mem::size_of_val(val)
             );
             ret
         }
     }
 
-    /// Create an owned `User<T>` from a raw pointer. The pointer should be
-    /// freeable with the `free` usercall and the alignment of `T`.
+    /// Create an owned `User<T>` from a raw pointer.
+    ///
+    /// # Safety
+    /// The caller must ensure `ptr` points to `T`, is freeable with the `free`
+    /// usercall and the alignment of `T`, and is uniquely owned.
     ///
     /// # Panics
     /// This function panics if:
@@ -154,7 +225,7 @@ pub fn new_from_enclave(val: &T) -> Self {
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw(ptr: *mut T) -> Self {
         T::check_ptr(ptr);
-        User(ptr as _)
+        User(NonNull::new_userref(ptr))
     }
 
     /// Convert this value into a raw pointer. The value will no longer be
@@ -162,24 +233,31 @@ pub unsafe fn from_raw(ptr: *mut T) -> Self {
     pub fn into_raw(self) -> *mut T {
         let ret = self.0;
         mem::forget(self);
-        ret as _
+        ret.as_ptr() as _
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T> User<T> where T: UserSafe {
+    /// Allocate space for `T` in user memory.
     pub fn uninitialized() -> Self {
         Self::new_uninit_bytes(mem::size_of::<T>())
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T> User<[T]> where [T]: UserSafe {
+    /// Allocate space for a `[T]` of `n` elements in user memory.
     pub fn uninitialized(n: usize) -> Self {
         Self::new_uninit_bytes(n * mem::size_of::<T>())
     }
 
     /// Create an owned `User<[T]>` from a raw thin pointer and a slice length.
-    /// The pointer should be freeable with the `free` usercall and the
-    /// alignment of `T`.
+    ///
+    /// # Safety
+    /// The caller must ensure `ptr` points to `len` elements of `T`, is
+    /// freeable with the `free` usercall and the alignment of `T`, and is
+    /// uniquely owned.
     ///
     /// # Panics
     /// This function panics if:
@@ -188,13 +266,17 @@ pub fn uninitialized(n: usize) -> Self {
     /// * The pointer is null
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
-        User(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as _)
+        User(NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>())))
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T: ?Sized> UserRef<T> where T: UserSafe {
     /// Create a `&UserRef<[T]>` from a raw pointer.
     ///
+    /// # Safety
+    /// The caller must ensure `ptr` points to `T`.
+    ///
     /// # Panics
     /// This function panics if:
     ///
@@ -206,7 +288,11 @@ pub unsafe fn from_ptr<'a>(ptr: *const T) -> &'a Self {
         &*(ptr as *const Self)
     }
 
-    /// Create a `&mut UserRef<[T]>` from a raw pointer.
+    /// Create a `&mut UserRef<[T]>` from a raw pointer. See the struct
+    /// documentation for the nuances regarding a `&mut UserRef<T>`.
+    ///
+    /// # Safety
+    /// The caller must ensure `ptr` points to `T`.
     ///
     /// # Panics
     /// This function panics if:
@@ -219,6 +305,8 @@ pub unsafe fn from_mut_ptr<'a>(ptr: *mut T) -> &'a mut Self {
         &mut*(ptr as *mut Self)
     }
 
+    /// Copy `val` into user memory.
+    ///
     /// # Panics
     /// This function panics if the destination doesn't have the same size as
     /// the source. This can happen for dynamically-sized types such as slices.
@@ -233,6 +321,8 @@ pub fn copy_from_enclave(&mut self, val: &T) {
         }
     }
 
+    /// Copy the value from user memory and place it into `dest`.
+    ///
     /// # Panics
     /// This function panics if the destination doesn't have the same size as
     /// the source. This can happen for dynamically-sized types such as slices.
@@ -247,24 +337,32 @@ pub fn copy_to_enclave(&self, dest: &mut T) {
         }
     }
 
+    /// Obtain a raw pointer from this reference.
     pub fn as_raw_ptr(&self) -> *const T {
         self as *const _ as _
     }
 
+    /// Obtain a raw pointer from this reference.
     pub fn as_raw_mut_ptr(&mut self) -> *mut T {
         self as *mut _ as _
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T> UserRef<T> where T: UserSafe {
+    /// Copy the value from user memory into enclave memory.
     pub fn to_enclave(&self) -> T {
         unsafe { ptr::read(self.0.get()) }
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T> UserRef<[T]> where [T]: UserSafe {
     /// Create a `&UserRef<[T]>` from a raw thin pointer and a slice length.
     ///
+    /// # Safety
+    /// The caller must ensure `ptr` points to `n` elements of `T`.
+    ///
     /// # Panics
     /// This function panics if:
     ///
@@ -272,10 +370,15 @@ impl<T> UserRef<[T]> where [T]: UserSafe {
     /// * The pointer is null
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
-        &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as *const Self)
+        &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self)
     }
 
     /// Create a `&mut UserRef<[T]>` from a raw thin pointer and a slice length.
+    /// See the struct documentation for the nuances regarding a
+    /// `&mut UserRef<T>`.
+    ///
+    /// # Safety
+    /// The caller must ensure `ptr` points to `n` elements of `T`.
     ///
     /// # Panics
     /// This function panics if:
@@ -284,21 +387,30 @@ pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
     /// * The pointer is null
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self {
-        &mut*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as *mut Self)
+        &mut*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self)
     }
 
+    /// Obtain a raw pointer to the first element of this user slice.
     pub fn as_ptr(&self) -> *const T {
         self.0.get() as _
     }
 
+    /// Obtain a raw pointer to the first element of this user slice.
     pub fn as_mut_ptr(&mut self) -> *mut T {
         self.0.get() as _
     }
 
+    /// Obtain the number of elements in this user slice.
     pub fn len(&self) -> usize {
         unsafe { (*self.0.get()).len() }
     }
 
+    /// Copy the value from user memory and place it into `dest`. Afterwards,
+    /// `dest` will contain exactly `self.len()` elements.
+    ///
+    /// # Panics
+    /// This function panics if the destination doesn't have the same size as
+    /// the source. This can happen for dynamically-sized types such as slices.
     pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) {
         unsafe {
             if let Some(missing) = self.len().checked_sub(dest.capacity()) {
@@ -309,12 +421,14 @@ pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) {
         }
     }
 
+    /// Copy the value from user memory into a vector in enclave memory.
     pub fn to_enclave(&self) -> Vec<T> {
         let mut ret = Vec::with_capacity(self.len());
         self.copy_to_enclave_vec(&mut ret);
         ret
     }
 
+    /// Returns an iterator over the slice.
     pub fn iter(&self) -> Iter<T>
         where T: UserSafe // FIXME: should be implied by [T]: UserSafe?
     {
@@ -323,6 +437,7 @@ pub fn iter(&self) -> Iter<T>
         }
     }
 
+    /// Returns an iterator that allows modifying each value.
     pub fn iter_mut(&mut self) -> IterMut<T>
         where T: UserSafe // FIXME: should be implied by [T]: UserSafe?
     {
@@ -332,8 +447,13 @@ pub fn iter_mut(&mut self) -> IterMut<T>
     }
 }
 
+/// Immutable user slice iterator
+///
+/// This struct is created by the `iter` method on `UserRef<[T]>`.
+#[unstable(feature = "sgx_platform", issue = "56975")]
 pub struct Iter<'a, T: 'a + UserSafe>(slice::Iter<'a, T>);
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<'a, T: UserSafe> Iterator for Iter<'a, T> {
     type Item = &'a UserRef<T>;
 
@@ -345,8 +465,13 @@ fn next(&mut self) -> Option<Self::Item> {
     }
 }
 
+/// Mutable user slice iterator
+///
+/// This struct is created by the `iter_mut` method on `UserRef<[T]>`.
+#[unstable(feature = "sgx_platform", issue = "56975")]
 pub struct IterMut<'a, T: 'a + UserSafe>(slice::IterMut<'a, T>);
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<'a, T: UserSafe> Iterator for IterMut<'a, T> {
     type Item = &'a mut UserRef<T>;
 
@@ -358,31 +483,36 @@ fn next(&mut self) -> Option<Self::Item> {
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T: ?Sized> Deref for User<T> where T: UserSafe {
     type Target = UserRef<T>;
 
     fn deref(&self) -> &Self::Target {
-        unsafe { &*self.0 }
+        unsafe { &*self.0.as_ptr() }
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T: ?Sized> DerefMut for User<T> where T: UserSafe {
     fn deref_mut(&mut self) -> &mut Self::Target {
-        unsafe { &mut*self.0 }
+        unsafe { &mut*self.0.as_ptr() }
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T: ?Sized> Drop for User<T> where T: UserSafe {
     fn drop(&mut self) {
         unsafe {
-            let ptr = (*self.0).0.get();
+            let ptr = (*self.0.as_ptr()).0.get();
             super::free(ptr as _, mem::size_of_val(&mut*ptr), T::align_of());
         }
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<UserRef<U>> for UserRef<T> {}
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T, I: SliceIndex<[T]>> Index<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
     type Output = UserRef<I::Output>;
 
@@ -394,6 +524,7 @@ fn index(&self, index: I) -> &UserRef<I::Output> {
     }
 }
 
+#[unstable(feature = "sgx_platform", issue = "56975")]
 impl<T, I: SliceIndex<[T]>> IndexMut<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
     #[inline]
     fn index_mut(&mut self, index: I) -> &mut UserRef<I::Output> {
@@ -402,3 +533,21 @@ fn index_mut(&mut self, index: I) -> &mut UserRef<I::Output> {
         }
     }
 }
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl UserRef<super::raw::ByteBuffer> {
+    /// Copy the user memory range pointed to by the user `ByteBuffer` to
+    /// enclave memory.
+    ///
+    /// # Panics
+    /// This function panics if:
+    ///
+    /// * The pointer in the user `ByteBuffer` is null
+    /// * The pointed-to range in the user `ByteBuffer` is not in user memory
+    pub fn copy_user_buffer(&self) -> Vec<u8> {
+        unsafe {
+            let buf = self.to_enclave();
+            User::from_raw_parts(buf.data as _, buf.len).to_enclave()
+        }
+    }
+}