#![allow(unused)]
use crate::arch::asm;
use crate::cell::UnsafeCell;
use crate::cmp;
use crate::mem;
use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut};
use crate::ptr::{self, NonNull};
use crate::slice;
use crate::slice::SliceIndex;
use super::super::mem::{is_enclave_range, is_user_range};
use fortanix_sgx_abi::*;
#[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 UserSafeSized for Cancel {}
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {}
#[unstable(feature = "sgx_platform", issue = "56975")]
pub unsafe trait UserSafe {
fn align_of() -> usize;
unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self;
unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> {
assert!(ptr.wrapping_add(size) >= ptr);
let ret = unsafe { Self::from_raw_sized_unchecked(ptr, size) };
unsafe {
Self::check_ptr(ret);
NonNull::new_unchecked(ret as _)
}
}
unsafe fn check_ptr(ptr: *const Self) {
let is_aligned = |p: *const u8| -> bool { p.is_aligned_to(Self::align_of()) };
assert!(is_aligned(ptr as *const u8));
assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr })));
assert!(!ptr.is_null());
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T: UserSafeSized> UserSafe for T {
fn align_of() -> usize {
mem::align_of::<T>()
}
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] {
fn align_of() -> usize {
mem::align_of::<T>()
}
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;
unsafe { slice::from_raw_parts_mut(ptr as _, len) }
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct UserRef<T: ?Sized>(UnsafeCell<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 {
unsafe { NonNull::new_unchecked(v as _) }
}
}
impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> {
unsafe fn new_userref(v: NonNull<T>) -> Self {
unsafe { NonNull::new_userref(v.as_ptr()) }
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> User<T>
where
T: UserSafe,
{
fn new_uninit_bytes(size: usize) -> Self {
unsafe {
let ptr = if size > 0 {
let alignment = cmp::max(T::align_of(), 8);
rtunwrap!(Ok, super::alloc(size, alignment)) as _
} else {
T::align_of() as _ };
if let Ok(v) = crate::panic::catch_unwind(|| T::from_raw_sized(ptr, size)) {
User(NonNull::new_userref(v))
} else {
rtabort!("Got invalid pointer from alloc() usercall")
}
}
}
pub fn new_from_enclave(val: &T) -> Self {
unsafe {
let mut user = Self::new_uninit_bytes(mem::size_of_val(val));
user.copy_from_enclave(val);
user
}
}
pub unsafe fn from_raw(ptr: *mut T) -> Self {
unsafe { T::check_ptr(ptr) };
User(unsafe { NonNull::new_userref(ptr) })
}
pub fn into_raw(self) -> *mut T {
let ret = self.0;
mem::forget(self);
ret.as_ptr() as _
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T> User<T>
where
T: UserSafe,
{
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,
{
pub fn uninitialized(n: usize) -> Self {
Self::new_uninit_bytes(n * mem::size_of::<T>())
}
pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
User(unsafe {
NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()))
})
}
}
fn region_as_aligned_chunks(ptr: *const u8, len: usize) -> (usize, usize, usize) {
let small0_size = if ptr.is_aligned_to(8) { 0 } else { 8 - ptr.addr() % 8 };
let small1_size = (len - small0_size) % 8;
let big_size = len - small0_size - small1_size;
(small0_size, big_size, small1_size)
}
unsafe fn copy_quadwords(src: *const u8, dst: *mut u8, len: usize) {
unsafe {
asm!(
"rep movsq (%rsi), (%rdi)",
inout("rcx") len / 8 => _,
inout("rdi") dst => _,
inout("rsi") src => _,
options(att_syntax, nostack, preserves_flags)
);
}
}
pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) {
unsafe fn copy_bytewise_to_userspace(src: *const u8, dst: *mut u8, len: usize) {
unsafe {
let mut seg_sel: u16 = 0;
for off in 0..len {
asm!("
mov %ds, ({seg_sel})
verw ({seg_sel})
movb {val}, ({dst})
mfence
lfence
",
val = in(reg_byte) *src.add(off),
dst = in(reg) dst.add(off),
seg_sel = in(reg) &mut seg_sel,
options(nostack, att_syntax)
);
}
}
}
assert!(!src.is_null());
assert!(!dst.is_null());
assert!(is_enclave_range(src, len));
assert!(is_user_range(dst, len));
assert!(len < isize::MAX as usize);
assert!(!src.addr().overflowing_add(len).1);
assert!(!dst.addr().overflowing_add(len).1);
if len < 8 {
unsafe {
copy_bytewise_to_userspace(src, dst, len);
}
} else if len % 8 == 0 && dst.is_aligned_to(8) {
unsafe {
copy_quadwords(src, dst, len);
}
} else {
let (small0_size, big_size, small1_size) = region_as_aligned_chunks(dst, len);
unsafe {
copy_bytewise_to_userspace(src, dst, small0_size);
let big_src = src.add(small0_size);
let big_dst = dst.add(small0_size);
copy_quadwords(big_src, big_dst, big_size);
let small1_src = src.add(big_size + small0_size);
let small1_dst = dst.add(big_size + small0_size);
copy_bytewise_to_userspace(small1_src, small1_dst, small1_size);
}
}
}
pub(crate) unsafe fn copy_from_userspace(src: *const u8, dst: *mut u8, len: usize) {
fn copy_misaligned_chunk_to_enclave(src: *const u8, dst: *mut u8, len: usize) {
let mut tmp_buff = [0u8; 16];
unsafe {
let pad0_size = src as usize % 8;
let aligned_src = src.sub(pad0_size);
let pad1_size = 8 - (src.add(len) as usize % 8);
let aligned_len = pad0_size + len + pad1_size;
debug_assert!(len < 8);
debug_assert_eq!(aligned_src as usize % 8, 0);
debug_assert_eq!(aligned_len % 8, 0);
debug_assert!(aligned_len <= 16);
copy_quadwords(aligned_src as _, tmp_buff.as_mut_ptr(), aligned_len);
ptr::copy(tmp_buff.as_ptr().add(pad0_size), dst, len);
}
}
assert!(!src.is_null());
assert!(!dst.is_null());
assert!(is_user_range(src, len));
assert!(is_enclave_range(dst, len));
assert!(!(src as usize).overflowing_add(len + 8).1);
assert!(!(dst as usize).overflowing_add(len + 8).1);
if len < 8 {
copy_misaligned_chunk_to_enclave(src, dst, len);
} else if len % 8 == 0 && src as usize % 8 == 0 {
unsafe {
copy_quadwords(src, dst, len);
}
} else {
let (small0_size, big_size, small1_size) = region_as_aligned_chunks(dst, len);
unsafe {
copy_misaligned_chunk_to_enclave(src, dst, small0_size);
let big_src = src.add(small0_size);
let big_dst = dst.add(small0_size);
copy_quadwords(big_src, big_dst, big_size);
let small1_src = src.add(big_size + small0_size);
let small1_dst = dst.add(big_size + small0_size);
copy_misaligned_chunk_to_enclave(small1_src, small1_dst, small1_size);
}
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> UserRef<T>
where
T: UserSafe,
{
pub unsafe fn from_ptr<'a>(ptr: *const T) -> &'a Self {
unsafe { T::check_ptr(ptr) };
unsafe { &*(ptr as *const Self) }
}
pub unsafe fn from_mut_ptr<'a>(ptr: *mut T) -> &'a mut Self {
unsafe { T::check_ptr(ptr) };
unsafe { &mut *(ptr as *mut Self) }
}
pub fn copy_from_enclave(&mut self, val: &T) {
unsafe {
assert_eq!(mem::size_of_val(val), mem::size_of_val(&*self.0.get()));
copy_to_userspace(
val as *const T as *const u8,
self.0.get() as *mut T as *mut u8,
mem::size_of_val(val),
);
}
}
pub fn copy_to_enclave(&self, dest: &mut T) {
unsafe {
assert_eq!(mem::size_of_val(dest), mem::size_of_val(&*self.0.get()));
copy_from_userspace(
self.0.get() as *const T as *const u8,
dest as *mut T as *mut u8,
mem::size_of_val(dest),
);
}
}
pub fn as_raw_ptr(&self) -> *const T {
self as *const _ as _
}
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,
{
pub fn to_enclave(&self) -> T {
unsafe {
let mut data: T = mem::MaybeUninit::uninit().assume_init();
copy_from_userspace(self.0.get() as _, &mut data as *mut T as _, mem::size_of::<T>());
data
}
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T> UserRef<[T]>
where
[T]: UserSafe,
{
pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
unsafe {
&*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self)
}
}
pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self {
unsafe {
&mut *(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self)
}
}
pub fn as_ptr(&self) -> *const T {
self.0.get() as _
}
pub fn as_mut_ptr(&mut self) -> *mut T {
self.0.get() as _
}
pub fn len(&self) -> usize {
unsafe { (*self.0.get()).len() }
}
pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) {
if let Some(missing) = self.len().checked_sub(dest.capacity()) {
dest.reserve(missing)
}
unsafe { dest.set_len(self.len()) };
self.copy_to_enclave(&mut dest[..]);
}
pub fn to_enclave(&self) -> Vec<T> {
let mut ret = Vec::with_capacity(self.len());
self.copy_to_enclave_vec(&mut ret);
ret
}
pub fn iter(&self) -> Iter<'_, T>
where
T: UserSafe, {
unsafe { Iter((&*self.as_raw_ptr()).iter()) }
}
pub fn iter_mut(&mut self) -> IterMut<'_, T>
where
T: UserSafe, {
unsafe { IterMut((&mut *self.as_raw_mut_ptr()).iter_mut()) }
}
}
#[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>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
unsafe { self.0.next().map(|e| UserRef::from_ptr(e)) }
}
}
#[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>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
unsafe { self.0.next().map(|e| UserRef::from_mut_ptr(e)) }
}
}
#[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.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.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.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> Index<I> for UserRef<[T]>
where
[T]: UserSafe,
I: SliceIndex<[T]>,
I::Output: UserSafe,
{
type Output = UserRef<I::Output>;
#[inline]
fn index(&self, index: I) -> &UserRef<I::Output> {
unsafe {
if let Some(slice) = index.get(&*self.as_raw_ptr()) {
UserRef::from_ptr(slice)
} else {
rtabort!("index out of range for user slice");
}
}
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T, I> IndexMut<I> for UserRef<[T]>
where
[T]: UserSafe,
I: SliceIndex<[T]>,
I::Output: UserSafe,
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut UserRef<I::Output> {
unsafe {
if let Some(slice) = index.get_mut(&mut *self.as_raw_mut_ptr()) {
UserRef::from_mut_ptr(slice)
} else {
rtabort!("index out of range for user slice");
}
}
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl UserRef<super::raw::ByteBuffer> {
pub fn copy_user_buffer(&self) -> Vec<u8> {
unsafe {
let buf = self.to_enclave();
if buf.len > 0 {
User::from_raw_parts(buf.data as _, buf.len).to_enclave()
} else {
Vec::with_capacity(0)
}
}
}
}