Skip to main content

std/sys/pal/sgx/abi/usercalls/
alloc.rs

1#![allow(unused)]
2
3use fortanix_sgx_abi::*;
4
5use super::super::mem::{is_enclave_range, is_user_range};
6use crate::arch::asm;
7use crate::cell::UnsafeCell;
8use crate::convert::TryInto;
9use crate::mem::{self, ManuallyDrop, MaybeUninit};
10use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut};
11use crate::ptr::{self, NonNull};
12use crate::slice::SliceIndex;
13use crate::{cmp, intrinsics, slice};
14
15/// A type that can be safely read from or written to userspace.
16///
17/// Non-exhaustive list of specific requirements for reading and writing:
18/// * **Type is `Copy`** (and therefore also not `Drop`). Copies will be
19///   created when copying from/to userspace. Destructors will not be called.
20/// * **No references or Rust-style owned pointers** (`Vec`, `Arc`, etc.). When
21///   reading from userspace, references into enclave memory must not be
22///   created. Also, only enclave memory is considered managed by the Rust
23///   compiler's static analysis. When reading from userspace, there can be no
24///   guarantee that the value correctly adheres to the expectations of the
25///   type. When writing to userspace, memory addresses of data in enclave
26///   memory must not be leaked for confidentiality reasons. `User` and
27///   `UserRef` are also not allowed for the same reasons.
28/// * **No fat pointers.** When reading from userspace, the size or vtable
29///   pointer could be automatically interpreted and used by the code. When
30///   writing to userspace, memory addresses of data in enclave memory (such
31///   as vtable pointers) must not be leaked for confidentiality reasons.
32///
33/// Non-exhaustive list of specific requirements for reading from userspace:
34/// * **Any bit pattern is valid** for this type (no `enum`s). There can be no
35///   guarantee that the value correctly adheres to the expectations of the
36///   type, so any value must be valid for this type.
37///
38/// Non-exhaustive list of specific requirements for writing to userspace:
39/// * **No pointers to enclave memory.** Memory addresses of data in enclave
40///   memory must not be leaked for confidentiality reasons.
41/// * **No internal padding.** Padding might contain previously-initialized
42///   secret data stored at that memory location and must not be leaked for
43///   confidentiality reasons.
44#[unstable(feature = "sgx_platform", issue = "56975")]
45pub unsafe trait UserSafeSized: Copy + Sized {}
46
47#[unstable(feature = "sgx_platform", issue = "56975")]
48unsafe impl UserSafeSized for u8 {}
49#[unstable(feature = "sgx_platform", issue = "56975")]
50unsafe impl<T> UserSafeSized for FifoDescriptor<T> {}
51#[unstable(feature = "sgx_platform", issue = "56975")]
52unsafe impl UserSafeSized for ByteBuffer {}
53#[unstable(feature = "sgx_platform", issue = "56975")]
54unsafe impl UserSafeSized for Usercall {}
55#[unstable(feature = "sgx_platform", issue = "56975")]
56unsafe impl UserSafeSized for Return {}
57#[unstable(feature = "sgx_platform", issue = "56975")]
58unsafe impl UserSafeSized for Cancel {}
59#[unstable(feature = "sgx_platform", issue = "56975")]
60unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {}
61
62/// A type that can be represented in memory as one or more `UserSafeSized`s.
63#[unstable(feature = "sgx_platform", issue = "56975")]
64pub unsafe trait UserSafe {
65    /// Equivalent to `align_of::<Self>`.
66    fn align_of() -> usize;
67
68    /// Constructs a pointer to `Self` given a memory range in user space.
69    ///
70    /// N.B., this takes a size, not a length!
71    ///
72    /// # Safety
73    ///
74    /// The caller must ensure the memory range is in user memory, is the
75    /// correct size and is correctly aligned and points to the right type.
76    unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self;
77
78    /// Constructs a pointer to `Self` given a memory range.
79    ///
80    /// N.B., this takes a size, not a length!
81    ///
82    /// # Safety
83    ///
84    /// The caller must ensure the memory range points to the correct type.
85    ///
86    /// # Panics
87    ///
88    /// This function panics if:
89    ///
90    /// * the pointer is not aligned.
91    /// * the pointer is null.
92    /// * the pointed-to range does not fit in the address space.
93    /// * the pointed-to range is not in user memory.
94    unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> {
95        assert!(ptr.wrapping_add(size) >= ptr);
96        // SAFETY: The caller has guaranteed the pointer is valid
97        let ret = unsafe { Self::from_raw_sized_unchecked(ptr, size) };
98        unsafe {
99            Self::check_ptr(ret);
100            NonNull::new_unchecked(ret as _)
101        }
102    }
103
104    /// Checks if a pointer may point to `Self` in user memory.
105    ///
106    /// # Safety
107    ///
108    /// The caller must ensure the memory range points to the correct type and
109    /// length (if this is a slice).
110    ///
111    /// # Panics
112    ///
113    /// This function panics if:
114    ///
115    /// * the pointer is not aligned.
116    /// * the pointer is null.
117    /// * the pointed-to range is not in user memory.
118    unsafe fn check_ptr(ptr: *const Self) {
119        let is_aligned = |p: *const u8| -> bool { p.is_aligned_to(Self::align_of()) };
120
121        assert!(is_aligned(ptr as *const u8));
122        assert!(is_user_range(ptr as _, size_of_val(unsafe { &*ptr })));
123        assert!(!ptr.is_null());
124    }
125}
126
127#[unstable(feature = "sgx_platform", issue = "56975")]
128unsafe impl<T: UserSafeSized> UserSafe for T {
129    fn align_of() -> usize {
130        align_of::<T>()
131    }
132
133    unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
134        assert_eq!(size, size_of::<T>());
135        ptr as _
136    }
137}
138
139#[unstable(feature = "sgx_platform", issue = "56975")]
140unsafe impl<T: UserSafeSized> UserSafe for [T] {
141    fn align_of() -> usize {
142        align_of::<T>()
143    }
144
145    /// # Panics
146    ///
147    /// This function panics if:
148    ///
149    /// * the element size is not a factor of the size
150    unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
151        let elem_size = size_of::<T>();
152        assert_eq!(size % elem_size, 0);
153        let len = size / elem_size;
154        ptr.cast::<T>().cast_slice(len)
155    }
156}
157
158/// A reference to some type in userspace memory. `&UserRef<T>` is equivalent
159/// to `&T` in enclave memory. Access to the memory is only allowed by copying
160/// to avoid TOCTTOU issues. After copying, code should make sure to completely
161/// check the value before use.
162///
163/// It is also possible to obtain a mutable reference `&mut UserRef<T>`. Unlike
164/// regular mutable references, these are not exclusive. Userspace may always
165/// write to the backing memory at any time, so it can't be assumed that there
166/// the pointed-to memory is uniquely borrowed. The two different reference types
167/// are used solely to indicate intent: a mutable reference is for writing to
168/// user memory, an immutable reference for reading from user memory.
169#[unstable(feature = "sgx_platform", issue = "56975")]
170#[repr(transparent)]
171pub struct UserRef<T: ?Sized>(UnsafeCell<T>);
172/// An owned type in userspace memory. `User<T>` is equivalent to `Box<T>` in
173/// enclave memory. Access to the memory is only allowed by copying to avoid
174/// TOCTTOU issues. The user memory will be freed when the value is dropped.
175/// After copying, code should make sure to completely check the value before
176/// use.
177#[unstable(feature = "sgx_platform", issue = "56975")]
178pub struct User<T: UserSafe + ?Sized>(NonNull<UserRef<T>>);
179
180#[unstable(feature = "sgx_platform", issue = "56975")]
181unsafe impl<T: UserSafeSized> Send for User<T> {}
182
183#[unstable(feature = "sgx_platform", issue = "56975")]
184unsafe impl<T: UserSafeSized> Send for User<[T]> {}
185
186trait NewUserRef<T: ?Sized> {
187    unsafe fn new_userref(v: T) -> Self;
188}
189
190impl<T: ?Sized> NewUserRef<*mut T> for NonNull<UserRef<T>> {
191    unsafe fn new_userref(v: *mut T) -> Self {
192        // SAFETY: The caller has guaranteed the pointer is valid
193        unsafe { NonNull::new_unchecked(v as _) }
194    }
195}
196
197impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> {
198    unsafe fn new_userref(v: NonNull<T>) -> Self {
199        // SAFETY: The caller has guaranteed the pointer is valid
200        unsafe { NonNull::new_userref(v.as_ptr()) }
201    }
202}
203
204/// A type which can a destination for safely copying from userspace.
205///
206/// # Safety
207///
208/// Requires that `T` and `Self` have identical layouts.
209#[unstable(feature = "sgx_platform", issue = "56975")]
210pub unsafe trait UserSafeCopyDestination<T: ?Sized> {
211    /// Returns a pointer for writing to the value.
212    fn as_mut_ptr(&mut self) -> *mut T;
213}
214
215#[unstable(feature = "sgx_platform", issue = "56975")]
216unsafe impl<T> UserSafeCopyDestination<T> for T {
217    fn as_mut_ptr(&mut self) -> *mut T {
218        self as _
219    }
220}
221
222#[unstable(feature = "sgx_platform", issue = "56975")]
223unsafe impl<T> UserSafeCopyDestination<[T]> for [T] {
224    fn as_mut_ptr(&mut self) -> *mut [T] {
225        self as _
226    }
227}
228
229#[unstable(feature = "sgx_platform", issue = "56975")]
230unsafe impl<T> UserSafeCopyDestination<T> for MaybeUninit<T> {
231    fn as_mut_ptr(&mut self) -> *mut T {
232        self as *mut Self as _
233    }
234}
235
236#[unstable(feature = "sgx_platform", issue = "56975")]
237unsafe impl<T> UserSafeCopyDestination<[T]> for [MaybeUninit<T>] {
238    fn as_mut_ptr(&mut self) -> *mut [T] {
239        self as *mut Self as _
240    }
241}
242
243#[unstable(feature = "sgx_platform", issue = "56975")]
244impl<T: ?Sized> User<T>
245where
246    T: UserSafe,
247{
248    // This function returns memory that is practically uninitialized, but is
249    // not considered "unspecified" or "undefined" for purposes of an
250    // optimizing compiler. This is achieved by returning a pointer from
251    // from outside as obtained by `super::alloc`.
252    fn new_uninit_bytes(size: usize) -> Self {
253        unsafe {
254            // Mustn't call alloc with size 0.
255            let ptr = if size > 0 {
256                rtunwrap!(Ok, super::alloc(size, T::align_of())) as _
257            } else {
258                crate::ptr::dangling_mut() // dangling pointer ok for size 0
259            };
260            if let Ok(v) = crate::panic::catch_unwind(|| T::from_raw_sized(ptr, size)) {
261                User(NonNull::new_userref(v))
262            } else {
263                rtabort!("Got invalid pointer from alloc() usercall")
264            }
265        }
266    }
267
268    /// Copies `val` into freshly allocated space in user memory.
269    pub fn new_from_enclave(val: &T) -> Self {
270        unsafe {
271            let mut user = Self::new_uninit_bytes(size_of_val(val));
272            user.copy_from_enclave(val);
273            user
274        }
275    }
276
277    /// Creates an owned `User<T>` from a raw pointer.
278    ///
279    /// # Safety
280    /// The caller must ensure `ptr` points to `T`, is freeable with the `free`
281    /// usercall and the alignment of `T`, and is uniquely owned.
282    ///
283    /// # Panics
284    /// This function panics if:
285    ///
286    /// * The pointer is not aligned
287    /// * The pointer is null
288    /// * The pointed-to range is not in user memory
289    pub unsafe fn from_raw(ptr: *mut T) -> Self {
290        // SAFETY: the caller must uphold the safety contract for `from_raw`.
291        unsafe { T::check_ptr(ptr) };
292        User(unsafe { NonNull::new_userref(ptr) })
293    }
294
295    /// Converts this value into a raw pointer. The value will no longer be
296    /// automatically freed.
297    pub fn into_raw(self) -> *mut T {
298        ManuallyDrop::new(self).0.as_ptr() as _
299    }
300}
301
302#[unstable(feature = "sgx_platform", issue = "56975")]
303impl<T> User<T>
304where
305    T: UserSafe,
306{
307    /// Allocates space for `T` in user memory.
308    pub fn uninitialized() -> Self {
309        Self::new_uninit_bytes(size_of::<T>())
310    }
311}
312
313#[unstable(feature = "sgx_platform", issue = "56975")]
314impl<T> User<[T]>
315where
316    [T]: UserSafe,
317{
318    /// Allocates space for a `[T]` of `n` elements in user memory.
319    pub fn uninitialized(n: usize) -> Self {
320        Self::new_uninit_bytes(n * size_of::<T>())
321    }
322
323    /// Creates an owned `User<[T]>` from a raw thin pointer and a slice length.
324    ///
325    /// # Safety
326    /// The caller must ensure `ptr` points to `len` elements of `T`, is
327    /// freeable with the `free` usercall and the alignment of `T`, and is
328    /// uniquely owned.
329    ///
330    /// # Panics
331    /// This function panics if:
332    ///
333    /// * The pointer is not aligned
334    /// * The pointer is null
335    /// * The pointed-to range does not fit in the address space
336    /// * The pointed-to range is not in user memory
337    pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
338        User(unsafe { NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * size_of::<T>())) })
339    }
340}
341
342/// Divide the slice `(ptr, len)` into three parts, where the middle part is
343/// aligned to `u64`.
344///
345/// The return values `(prefix_len, mid_len, suffix_len)` add back up to `len`.
346/// The return values are such that the memory region `(ptr + prefix_len,
347/// mid_len)` is the largest possible region where `ptr + prefix_len` is aligned
348/// to `u64` and `mid_len` is a multiple of the byte size of `u64`. This means
349/// that `prefix_len` and `suffix_len` are guaranteed to be less than the byte
350/// size of `u64`, and that `(ptr, prefix_len)` and `(ptr + prefix_len +
351/// mid_len, suffix_len)` don't straddle an alignment boundary.
352// Standard Rust functions such as `<[u8]>::align_to::<u64>` and
353// `<*const u8>::align_offset` aren't _guaranteed_ to compute the largest
354// possible middle region, and as such can't be used.
355fn u64_align_to_guaranteed(ptr: *const u8, mut len: usize) -> (usize, usize, usize) {
356    const QWORD_SIZE: usize = size_of::<u64>();
357
358    let offset = ptr as usize % QWORD_SIZE;
359
360    let prefix_len = if intrinsics::unlikely(offset > 0) { QWORD_SIZE - offset } else { 0 };
361
362    len = match len.checked_sub(prefix_len) {
363        Some(remaining_len) => remaining_len,
364        None => return (len, 0, 0),
365    };
366
367    let suffix_len = len % QWORD_SIZE;
368    len -= suffix_len;
369
370    (prefix_len, len, suffix_len)
371}
372
373unsafe fn copy_quadwords(src: *const u8, dst: *mut u8, len: usize) {
374    unsafe {
375        asm!(
376            "rep movsq (%rsi), (%rdi)",
377            inout("rcx") len / 8 => _,
378            inout("rdi") dst => _,
379            inout("rsi") src => _,
380            options(att_syntax, nostack, preserves_flags)
381        );
382    }
383}
384
385/// Copies `len` bytes of data from enclave pointer `src` to userspace `dst`
386///
387/// This function mitigates stale data vulnerabilities by ensuring all writes to untrusted memory are either:
388///  - preceded by the VERW instruction and followed by the MFENCE; LFENCE instruction sequence
389///  - or are in multiples of 8 bytes, aligned to an 8-byte boundary
390///
391/// # Panics
392/// This function panics if:
393///
394/// * The `src` pointer is null
395/// * The `dst` pointer is null
396/// * The `src` memory range is not in enclave memory
397/// * The `dst` memory range is not in user memory
398///
399/// # References
400///  - https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html
401///  - https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/processor-mmio-stale-data-vulnerabilities.html#inpage-nav-3-2-2
402pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) {
403    /// Like `ptr::copy(src, dst, len)`, except it uses the Intel-recommended
404    /// instruction sequence for unaligned writes.
405    unsafe fn write_bytewise_to_userspace(src: *const u8, dst: *mut u8, len: usize) {
406        if intrinsics::likely(len == 0) {
407            return;
408        }
409
410        unsafe {
411            let mut seg_sel: u16 = 0;
412            for off in 0..len {
413                asm!("
414                    mov %ds, ({seg_sel})
415                    verw ({seg_sel})
416                    movb {val}, ({dst})
417                    mfence
418                    lfence
419                    ",
420                    val = in(reg_byte) *src.add(off),
421                    dst = in(reg) dst.add(off),
422                    seg_sel = in(reg) &mut seg_sel,
423                    options(nostack, att_syntax)
424                );
425            }
426        }
427    }
428
429    assert!(!src.is_null());
430    assert!(!dst.is_null());
431    assert!(is_enclave_range(src, len));
432    assert!(is_user_range(dst, len));
433    assert!(len < isize::MAX as usize);
434    assert!(!src.addr().overflowing_add(len).1);
435    assert!(!dst.addr().overflowing_add(len).1);
436
437    unsafe {
438        let (len1, len2, len3) = u64_align_to_guaranteed(dst, len);
439        let (src1, dst1) = (src, dst);
440        let (src2, dst2) = (src1.add(len1), dst1.add(len1));
441        let (src3, dst3) = (src2.add(len2), dst2.add(len2));
442
443        write_bytewise_to_userspace(src1, dst1, len1);
444        copy_quadwords(src2, dst2, len2);
445        write_bytewise_to_userspace(src3, dst3, len3);
446    }
447}
448
449/// Copies `len` bytes of data from userspace pointer `src` to enclave pointer `dst`
450///
451/// This function mitigates AEPIC leak vulnerabilities by ensuring all reads from untrusted memory are 8-byte aligned
452///
453/// # Panics
454/// This function panics if:
455///
456/// * The `src` pointer is null
457/// * The `dst` pointer is null
458/// * The `src` memory range is not in user memory
459/// * The `dst` memory range is not in enclave memory
460///
461/// # References
462///  - https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00657.html
463///  - https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/stale-data-read-from-xapic.html
464pub(crate) unsafe fn copy_from_userspace(src: *const u8, dst: *mut u8, len: usize) {
465    /// Like `ptr::copy(src, dst, len)`, except it uses only u64-aligned reads.
466    ///
467    /// # Safety
468    /// The source memory region must not straddle an alignment boundary.
469    unsafe fn read_misaligned_from_userspace(src: *const u8, dst: *mut u8, len: usize) {
470        if intrinsics::likely(len == 0) {
471            return;
472        }
473
474        unsafe {
475            let offset: usize;
476            let data: u64;
477            // doing a memory read that's potentially out of bounds for `src`,
478            // this isn't supported by Rust, so have to use assembly
479            asm!("
480                movl {src:e}, {offset:e}
481                andl $7, {offset:e}
482                andq $-8, {src}
483                movq ({src}), {dst}
484                ",
485                src = inout(reg) src => _,
486                offset = out(reg) offset,
487                dst = out(reg) data,
488                options(nostack, att_syntax, readonly, pure)
489            );
490            let data = data.to_le_bytes();
491            ptr::copy_nonoverlapping(data.as_ptr().add(offset), dst, len);
492        }
493    }
494
495    assert!(!src.is_null());
496    assert!(!dst.is_null());
497    assert!(is_user_range(src, len));
498    assert!(is_enclave_range(dst, len));
499    assert!(len < isize::MAX as usize);
500    assert!(!(src as usize).overflowing_add(len).1);
501    assert!(!(dst as usize).overflowing_add(len).1);
502
503    unsafe {
504        let (len1, len2, len3) = u64_align_to_guaranteed(src, len);
505        let (src1, dst1) = (src, dst);
506        let (src2, dst2) = (src1.add(len1), dst1.add(len1));
507        let (src3, dst3) = (src2.add(len2), dst2.add(len2));
508
509        read_misaligned_from_userspace(src1, dst1, len1);
510        copy_quadwords(src2, dst2, len2);
511        read_misaligned_from_userspace(src3, dst3, len3);
512    }
513}
514
515#[unstable(feature = "sgx_platform", issue = "56975")]
516impl<T: ?Sized> UserRef<T>
517where
518    T: UserSafe,
519{
520    /// Creates a `&UserRef<[T]>` from a raw pointer.
521    ///
522    /// # Safety
523    /// The caller must ensure `ptr` points to `T`.
524    ///
525    /// # Panics
526    /// This function panics if:
527    ///
528    /// * The pointer is not aligned
529    /// * The pointer is null
530    /// * The pointed-to range is not in user memory
531    pub unsafe fn from_ptr<'a>(ptr: *const T) -> &'a Self {
532        // SAFETY: The caller must uphold the safety contract for `from_ptr`.
533        unsafe { T::check_ptr(ptr) };
534        unsafe { &*(ptr as *const Self) }
535    }
536
537    /// Creates a `&mut UserRef<[T]>` from a raw pointer. See the struct
538    /// documentation for the nuances regarding a `&mut UserRef<T>`.
539    ///
540    /// # Safety
541    /// The caller must ensure `ptr` points to `T`.
542    ///
543    /// # Panics
544    /// This function panics if:
545    ///
546    /// * The pointer is not aligned
547    /// * The pointer is null
548    /// * The pointed-to range is not in user memory
549    pub unsafe fn from_mut_ptr<'a>(ptr: *mut T) -> &'a mut Self {
550        // SAFETY: The caller must uphold the safety contract for `from_mut_ptr`.
551        unsafe { T::check_ptr(ptr) };
552        unsafe { &mut *(ptr as *mut Self) }
553    }
554
555    /// Copies `val` into user memory.
556    ///
557    /// # Panics
558    /// This function panics if the destination doesn't have the same size as
559    /// the source. This can happen for dynamically-sized types such as slices.
560    pub fn copy_from_enclave(&mut self, val: &T) {
561        unsafe {
562            assert_eq!(size_of_val(val), size_of_val(&*self.0.get()));
563            copy_to_userspace(
564                val as *const T as *const u8,
565                self.0.get() as *mut T as *mut u8,
566                size_of_val(val),
567            );
568        }
569    }
570
571    /// Copies the value from user memory and place it into `dest`.
572    ///
573    /// # Panics
574    /// This function panics if the destination doesn't have the same size as
575    /// the source. This can happen for dynamically-sized types such as slices.
576    pub fn copy_to_enclave<U: ?Sized + UserSafeCopyDestination<T>>(&self, dest: &mut U) {
577        unsafe {
578            assert_eq!(size_of_val(dest), size_of_val(&*self.0.get()));
579            copy_from_userspace(
580                self.0.get() as *const T as *const u8,
581                dest.as_mut_ptr() as *mut u8,
582                size_of_val(dest),
583            );
584        }
585    }
586
587    /// Obtain a raw pointer from this reference.
588    pub fn as_raw_ptr(&self) -> *const T {
589        self as *const _ as _
590    }
591
592    /// Obtain a raw pointer from this reference.
593    pub fn as_raw_mut_ptr(&mut self) -> *mut T {
594        self as *mut _ as _
595    }
596}
597
598#[unstable(feature = "sgx_platform", issue = "56975")]
599impl<T> UserRef<T>
600where
601    T: UserSafe,
602{
603    /// Copies the value from user memory into enclave memory.
604    pub fn to_enclave(&self) -> T {
605        unsafe {
606            let mut data = mem::MaybeUninit::uninit();
607            copy_from_userspace(self.0.get() as _, data.as_mut_ptr() as _, size_of::<T>());
608            data.assume_init()
609        }
610    }
611}
612
613#[unstable(feature = "sgx_platform", issue = "56975")]
614impl<T> UserRef<[T]>
615where
616    [T]: UserSafe,
617{
618    /// Creates a `&UserRef<[T]>` from a raw thin pointer and a slice length.
619    ///
620    /// # Safety
621    /// The caller must ensure `ptr` points to `n` elements of `T`.
622    ///
623    /// # Panics
624    /// This function panics if:
625    ///
626    /// * The pointer is not aligned
627    /// * The pointer is null
628    /// * The pointed-to range does not fit in the address space
629    /// * The pointed-to range is not in user memory
630    pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
631        // SAFETY: The caller must uphold the safety contract for `from_raw_parts`.
632        unsafe { &*(<[T]>::from_raw_sized(ptr as _, len * size_of::<T>()).as_ptr() as *const Self) }
633    }
634
635    /// Creates a `&mut UserRef<[T]>` from a raw thin pointer and a slice length.
636    /// See the struct documentation for the nuances regarding a
637    /// `&mut UserRef<T>`.
638    ///
639    /// # Safety
640    /// The caller must ensure `ptr` points to `n` elements of `T`.
641    ///
642    /// # Panics
643    /// This function panics if:
644    ///
645    /// * The pointer is not aligned
646    /// * The pointer is null
647    /// * The pointed-to range does not fit in the address space
648    /// * The pointed-to range is not in user memory
649    pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self {
650        // SAFETY: The caller must uphold the safety contract for `from_raw_parts_mut`.
651        unsafe {
652            &mut *(<[T]>::from_raw_sized(ptr as _, len * size_of::<T>()).as_ptr() as *mut Self)
653        }
654    }
655
656    /// Obtain a raw pointer to the first element of this user slice.
657    pub fn as_ptr(&self) -> *const T {
658        self.0.get() as _
659    }
660
661    /// Obtain a raw pointer to the first element of this user slice.
662    pub fn as_mut_ptr(&mut self) -> *mut T {
663        self.0.get() as _
664    }
665
666    /// Obtain the number of elements in this user slice.
667    pub fn len(&self) -> usize {
668        unsafe { self.0.get().len() }
669    }
670
671    /// Copies the value from user memory and appends it to `dest`.
672    pub fn append_to_enclave_vec(&self, dest: &mut Vec<T>) {
673        dest.reserve(self.len());
674        self.copy_to_enclave(&mut dest.spare_capacity_mut()[..self.len()]);
675        // SAFETY: We reserve enough space above.
676        unsafe { dest.set_len(dest.len() + self.len()) };
677    }
678
679    /// Copies the value from user memory into a vector in enclave memory.
680    pub fn to_enclave(&self) -> Vec<T> {
681        let mut ret = Vec::with_capacity(self.len());
682        self.append_to_enclave_vec(&mut ret);
683        ret
684    }
685
686    /// Returns an iterator over the slice.
687    pub fn iter(&self) -> Iter<'_, T>
688    where
689        T: UserSafe, // FIXME: should be implied by [T]: UserSafe?
690    {
691        unsafe { Iter((&*self.as_raw_ptr()).iter()) }
692    }
693
694    /// Returns an iterator that allows modifying each value.
695    pub fn iter_mut(&mut self) -> IterMut<'_, T>
696    where
697        T: UserSafe, // FIXME: should be implied by [T]: UserSafe?
698    {
699        unsafe { IterMut((&mut *self.as_raw_mut_ptr()).iter_mut()) }
700    }
701}
702
703/// Immutable user slice iterator
704///
705/// This struct is created by the `iter` method on `UserRef<[T]>`.
706#[unstable(feature = "sgx_platform", issue = "56975")]
707pub struct Iter<'a, T: 'a + UserSafe>(slice::Iter<'a, T>);
708
709#[unstable(feature = "sgx_platform", issue = "56975")]
710impl<'a, T: UserSafe> Iterator for Iter<'a, T> {
711    type Item = &'a UserRef<T>;
712
713    #[inline]
714    fn next(&mut self) -> Option<Self::Item> {
715        unsafe { self.0.next().map(|e| UserRef::from_ptr(e)) }
716    }
717}
718
719/// Mutable user slice iterator
720///
721/// This struct is created by the `iter_mut` method on `UserRef<[T]>`.
722#[unstable(feature = "sgx_platform", issue = "56975")]
723pub struct IterMut<'a, T: 'a + UserSafe>(slice::IterMut<'a, T>);
724
725#[unstable(feature = "sgx_platform", issue = "56975")]
726impl<'a, T: UserSafe> Iterator for IterMut<'a, T> {
727    type Item = &'a mut UserRef<T>;
728
729    #[inline]
730    fn next(&mut self) -> Option<Self::Item> {
731        unsafe { self.0.next().map(|e| UserRef::from_mut_ptr(e)) }
732    }
733}
734
735#[unstable(feature = "sgx_platform", issue = "56975")]
736impl<T: ?Sized> Deref for User<T>
737where
738    T: UserSafe,
739{
740    type Target = UserRef<T>;
741
742    fn deref(&self) -> &Self::Target {
743        unsafe { &*self.0.as_ptr() }
744    }
745}
746
747#[unstable(feature = "sgx_platform", issue = "56975")]
748impl<T: ?Sized> DerefMut for User<T>
749where
750    T: UserSafe,
751{
752    fn deref_mut(&mut self) -> &mut Self::Target {
753        unsafe { &mut *self.0.as_ptr() }
754    }
755}
756
757#[unstable(feature = "sgx_platform", issue = "56975")]
758impl<T: ?Sized> Drop for User<T>
759where
760    T: UserSafe,
761{
762    fn drop(&mut self) {
763        unsafe {
764            let ptr = (*self.0.as_ptr()).0.get();
765            super::free(ptr as _, size_of_val(&mut *ptr), T::align_of());
766        }
767    }
768}
769
770#[unstable(feature = "sgx_platform", issue = "56975")]
771impl<T: CoerceUnsized<U>, U> CoerceUnsized<UserRef<U>> for UserRef<T> {}
772
773#[unstable(feature = "sgx_platform", issue = "56975")]
774impl<T, I> Index<I> for UserRef<[T]>
775where
776    [T]: UserSafe,
777    I: SliceIndex<[T]>,
778    I::Output: UserSafe,
779{
780    type Output = UserRef<I::Output>;
781
782    #[inline]
783    fn index(&self, index: I) -> &UserRef<I::Output> {
784        unsafe {
785            if let Some(slice) = index.get(&*self.as_raw_ptr()) {
786                UserRef::from_ptr(slice)
787            } else {
788                rtabort!("index out of range for user slice");
789            }
790        }
791    }
792}
793
794#[unstable(feature = "sgx_platform", issue = "56975")]
795impl<T, I> IndexMut<I> for UserRef<[T]>
796where
797    [T]: UserSafe,
798    I: SliceIndex<[T]>,
799    I::Output: UserSafe,
800{
801    #[inline]
802    fn index_mut(&mut self, index: I) -> &mut UserRef<I::Output> {
803        unsafe {
804            if let Some(slice) = index.get_mut(&mut *self.as_raw_mut_ptr()) {
805                UserRef::from_mut_ptr(slice)
806            } else {
807                rtabort!("index out of range for user slice");
808            }
809        }
810    }
811}
812
813#[unstable(feature = "sgx_platform", issue = "56975")]
814impl UserRef<super::raw::ByteBuffer> {
815    /// Copies the user memory range pointed to by the user `ByteBuffer` to
816    /// enclave memory.
817    ///
818    /// # Panics
819    /// This function panics if, in the user `ByteBuffer`:
820    ///
821    /// * The pointer is null
822    /// * The pointed-to range does not fit in the address space
823    /// * The pointed-to range is not in user memory
824    pub fn copy_user_buffer(&self) -> Vec<u8> {
825        unsafe {
826            let buf = self.to_enclave();
827            if buf.len > 0 {
828                User::from_raw_parts(buf.data as _, buf.len).to_enclave()
829            } else {
830                // Mustn't look at `data` or call `free` if `len` is `0`.
831                Vec::with_capacity(0)
832            }
833        }
834    }
835}