#![allow(unused)]
+use crate::arch::asm;
use crate::cell::UnsafeCell;
+use crate::convert::TryInto;
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_user_range;
+use super::super::mem::{is_enclave_range, is_user_range};
use fortanix_sgx_abi::*;
/// A type that can be safely read from or written to userspace.
}
}
+/// Copies `len` bytes of data from enclave pointer `src` to userspace `dst`
+///
+/// This function mitigates stale data vulnerabilities
+/// https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html
+///
+/// # Panics
+/// This function panics if:
+///
+/// * The `src` pointer is null
+/// * The `dst` pointer is null
+/// * The `src` memory range is not in enclave memory
+/// * The `dst` memory range is not in user memory
+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 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.offset(off as isize),
+ dst = in(reg) dst.offset(off as isize),
+ seg_sel = in(reg) &seg_sel,
+ options(nostack, att_syntax)
+ );
+ }
+ }
+ }
+
+ unsafe fn copy_aligned_quadwords_to_userspace(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)
+ );
+ }
+ }
+ 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 as usize).overflowing_add(len).1);
+ assert!(!(dst as usize).overflowing_add(len).1);
+
+ if len < 8 {
+ // Can't align on 8 byte boundary: copy safely byte per byte
+ unsafe {
+ copy_bytewise_to_userspace(src, dst, len);
+ }
+ } else if len % 8 == 0 && dst as usize % 8 == 0 {
+ // Copying 8-byte aligned quadwords: copy quad word per quad word
+ unsafe {
+ copy_aligned_quadwords_to_userspace(src, dst, len);
+ }
+ } else {
+ // Split copies into three parts:
+ // +--------+
+ // | small0 | Chunk smaller than 8 bytes
+ // +--------+
+ // | big | Chunk 8-byte aligned, and size a multiple of 8 bytes
+ // +--------+
+ // | small1 | Chunk smaller than 8 bytes
+ // +--------+
+
+ unsafe {
+ // Copy small0
+ let small0_size = (8 - dst as usize % 8) as u8;
+ let small0_src = src;
+ let small0_dst = dst;
+ copy_bytewise_to_userspace(small0_src as _, small0_dst, small0_size as _);
+
+ // Copy big
+ let small1_size = ((len - small0_size as usize) % 8) as u8;
+ let big_size = len - small0_size as usize - small1_size as usize;
+ let big_src = src.offset(small0_size as _);
+ let big_dst = dst.offset(small0_size as _);
+ copy_aligned_quadwords_to_userspace(big_src as _, big_dst, big_size);
+
+ // Copy small1
+ let small1_src = src.offset(big_size as isize + small0_size as isize);
+ let small1_dst = dst.offset(big_size as isize + small0_size as isize);
+ copy_bytewise_to_userspace(small1_src, small1_dst, small1_size as _);
+ }
+ }
+}
+
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> UserRef<T>
where
pub fn copy_from_enclave(&mut self, val: &T) {
unsafe {
assert_eq!(mem::size_of_val(val), mem::size_of_val(&*self.0.get()));
- ptr::copy(
+ copy_to_userspace(
val as *const T as *const u8,
self.0.get() as *mut T as *mut u8,
mem::size_of_val(val),