]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/sgx/abi/usercalls/alloc.rs
Fix potential integer overflow in SGX memory range calculation.
[rust.git] / src / libstd / sys / sgx / abi / usercalls / alloc.rs
1 #![allow(unused)]
2
3 use crate::ptr::{self, NonNull};
4 use crate::mem;
5 use crate::cell::UnsafeCell;
6 use crate::slice;
7 use crate::ops::{Deref, DerefMut, Index, IndexMut, CoerceUnsized};
8 use crate::slice::SliceIndex;
9
10 use fortanix_sgx_abi::*;
11 use super::super::mem::is_user_range;
12
13 /// A type that can be safely read from or written to userspace.
14 ///
15 /// Non-exhaustive list of specific requirements for reading and writing:
16 /// * **Type is `Copy`** (and therefore also not `Drop`). Copies will be
17 ///   created when copying from/to userspace. Destructors will not be called.
18 /// * **No references or Rust-style owned pointers** (`Vec`, `Arc`, etc.). When
19 ///   reading from userspace, references into enclave memory must not be
20 ///   created. Also, only enclave memory is considered managed by the Rust
21 ///   compiler's static analysis. When reading from userspace, there can be no
22 ///   guarantee that the value correctly adheres to the expectations of the
23 ///   type. When writing to userspace, memory addresses of data in enclave
24 ///   memory must not be leaked for confidentiality reasons. `User` and
25 ///   `UserRef` are also not allowed for the same reasons.
26 /// * **No fat pointers.** When reading from userspace, the size or vtable
27 ///   pointer could be automatically interpreted and used by the code. When
28 ///   writing to userspace, memory addresses of data in enclave memory (such
29 ///   as vtable pointers) must not be leaked for confidentiality reasons.
30 ///
31 /// Non-exhaustive list of specific requirements for reading from userspace:
32 /// * **Any bit pattern is valid** for this type (no `enum`s). There can be no
33 ///   guarantee that the value correctly adheres to the expectations of the
34 ///   type, so any value must be valid for this type.
35 ///
36 /// Non-exhaustive list of specific requirements for writing to userspace:
37 /// * **No pointers to enclave memory.** Memory addresses of data in enclave
38 ///   memory must not be leaked for confidentiality reasons.
39 /// * **No internal padding.** Padding might contain previously-initialized
40 ///   secret data stored at that memory location and must not be leaked for
41 ///   confidentiality reasons.
42 #[unstable(feature = "sgx_platform", issue = "56975")]
43 pub unsafe trait UserSafeSized: Copy + Sized {}
44
45 #[unstable(feature = "sgx_platform", issue = "56975")]
46 unsafe impl UserSafeSized for u8 {}
47 #[unstable(feature = "sgx_platform", issue = "56975")]
48 unsafe impl<T> UserSafeSized for FifoDescriptor<T> {}
49 #[unstable(feature = "sgx_platform", issue = "56975")]
50 unsafe impl UserSafeSized for ByteBuffer {}
51 #[unstable(feature = "sgx_platform", issue = "56975")]
52 unsafe impl UserSafeSized for Usercall {}
53 #[unstable(feature = "sgx_platform", issue = "56975")]
54 unsafe impl UserSafeSized for Return {}
55 #[unstable(feature = "sgx_platform", issue = "56975")]
56 unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {}
57
58 /// A type that can be represented in memory as one or more `UserSafeSized`s.
59 #[unstable(feature = "sgx_platform", issue = "56975")]
60 pub unsafe trait UserSafe {
61     /// Equivalent to `mem::align_of::<Self>`.
62     fn align_of() -> usize;
63
64     /// Construct a pointer to `Self` given a memory range in user space.
65     ///
66     /// N.B., this takes a size, not a length!
67     ///
68     /// # Safety
69     ///
70     /// The caller must ensure the memory range is in user memory, is the
71     /// correct size and is correctly aligned and points to the right type.
72     unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self;
73
74     /// Construct a pointer to `Self` given a memory range.
75     ///
76     /// N.B., this takes a size, not a length!
77     ///
78     /// # Safety
79     ///
80     /// The caller must ensure the memory range points to the correct type.
81     ///
82     /// # Panics
83     ///
84     /// This function panics if:
85     ///
86     /// * the pointer is not aligned.
87     /// * the pointer is null.
88     /// * the pointed-to range does not fit in the address space.
89     /// * the pointed-to range is not in user memory.
90     unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> {
91         assert!(ptr.wrapping_add(size) >= ptr);
92         let ret = Self::from_raw_sized_unchecked(ptr, size);
93         Self::check_ptr(ret);
94         NonNull::new_unchecked(ret as _)
95     }
96
97     /// Checks if a pointer may point to `Self` in user memory.
98     ///
99     /// # Safety
100     ///
101     /// The caller must ensure the memory range points to the correct type and
102     /// length (if this is a slice).
103     ///
104     /// # Panics
105     ///
106     /// This function panics if:
107     ///
108     /// * the pointer is not aligned.
109     /// * the pointer is null.
110     /// * the pointed-to range is not in user memory.
111     unsafe fn check_ptr(ptr: *const Self) {
112         let is_aligned = |p| -> bool {
113             0 == (p as usize) & (Self::align_of() - 1)
114         };
115
116         assert!(is_aligned(ptr as *const u8));
117         assert!(is_user_range(ptr as _, mem::size_of_val(&*ptr)));
118         assert!(!ptr.is_null());
119     }
120 }
121
122 #[unstable(feature = "sgx_platform", issue = "56975")]
123 unsafe impl<T: UserSafeSized> UserSafe for T {
124     fn align_of() -> usize {
125         mem::align_of::<T>()
126     }
127
128     unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
129         assert_eq!(size, mem::size_of::<T>());
130         ptr as _
131     }
132 }
133
134 #[unstable(feature = "sgx_platform", issue = "56975")]
135 unsafe impl<T: UserSafeSized> UserSafe for [T] {
136     fn align_of() -> usize {
137         mem::align_of::<T>()
138     }
139
140     unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
141         let elem_size = mem::size_of::<T>();
142         assert_eq!(size % elem_size, 0);
143         let len = size / elem_size;
144         slice::from_raw_parts_mut(ptr as _, len)
145     }
146 }
147
148 /// A reference to some type in userspace memory. `&UserRef<T>` is equivalent
149 /// to `&T` in enclave memory. Access to the memory is only allowed by copying
150 /// to avoid TOCTTOU issues. After copying, code should make sure to completely
151 /// check the value before use.
152 ///
153 /// It is also possible to obtain a mutable reference `&mut UserRef<T>`. Unlike
154 /// regular mutable references, these are not exclusive. Userspace may always
155 /// write to the backing memory at any time, so it can't be assumed that there
156 /// the pointed-to memory is uniquely borrowed. The two different refence types
157 /// are used solely to indicate intent: a mutable reference is for writing to
158 /// user memory, an immutable reference for reading from user memory.
159 #[unstable(feature = "sgx_platform", issue = "56975")]
160 pub struct UserRef<T: ?Sized>(UnsafeCell<T>);
161 /// An owned type in userspace memory. `User<T>` is equivalent to `Box<T>` in
162 /// enclave memory. Access to the memory is only allowed by copying to avoid
163 /// TOCTTOU issues. The user memory will be freed when the value is dropped.
164 /// After copying, code should make sure to completely check the value before
165 /// use.
166 #[unstable(feature = "sgx_platform", issue = "56975")]
167 pub struct User<T: UserSafe + ?Sized>(NonNull<UserRef<T>>);
168
169 trait NewUserRef<T: ?Sized> {
170     unsafe fn new_userref(v: T) -> Self;
171 }
172
173 impl<T: ?Sized> NewUserRef<*mut T> for NonNull<UserRef<T>> {
174     unsafe fn new_userref(v: *mut T) -> Self {
175         NonNull::new_unchecked(v as _)
176     }
177 }
178
179 impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> {
180     unsafe fn new_userref(v: NonNull<T>) -> Self {
181         NonNull::new_userref(v.as_ptr())
182     }
183 }
184
185 #[unstable(feature = "sgx_platform", issue = "56975")]
186 impl<T: ?Sized> User<T> where T: UserSafe {
187     // This function returns memory that is practically uninitialized, but is
188     // not considered "unspecified" or "undefined" for purposes of an
189     // optimizing compiler. This is achieved by returning a pointer from
190     // from outside as obtained by `super::alloc`.
191     fn new_uninit_bytes(size: usize) -> Self {
192         unsafe {
193             // Mustn't call alloc with size 0.
194             let ptr = if size > 0 {
195                 rtunwrap!(Ok, super::alloc(size, T::align_of())) as _
196             } else {
197                 T::align_of() as _ // dangling pointer ok for size 0
198             };
199             if let Ok(v) = crate::panic::catch_unwind(|| T::from_raw_sized(ptr, size)) {
200                 User(NonNull::new_userref(v))
201             } else {
202                 rtabort!("Got invalid pointer from alloc() usercall")
203             }
204         }
205     }
206
207     /// Copies `val` into freshly allocated space in user memory.
208     pub fn new_from_enclave(val: &T) -> Self {
209         unsafe {
210             let ret = Self::new_uninit_bytes(mem::size_of_val(val));
211             ptr::copy(
212                 val as *const T as *const u8,
213                 ret.0.as_ptr() as *mut u8,
214                 mem::size_of_val(val)
215             );
216             ret
217         }
218     }
219
220     /// Creates an owned `User<T>` from a raw pointer.
221     ///
222     /// # Safety
223     /// The caller must ensure `ptr` points to `T`, is freeable with the `free`
224     /// usercall and the alignment of `T`, and is uniquely owned.
225     ///
226     /// # Panics
227     /// This function panics if:
228     ///
229     /// * The pointer is not aligned
230     /// * The pointer is null
231     /// * The pointed-to range is not in user memory
232     pub unsafe fn from_raw(ptr: *mut T) -> Self {
233         T::check_ptr(ptr);
234         User(NonNull::new_userref(ptr))
235     }
236
237     /// Converts this value into a raw pointer. The value will no longer be
238     /// automatically freed.
239     pub fn into_raw(self) -> *mut T {
240         let ret = self.0;
241         mem::forget(self);
242         ret.as_ptr() as _
243     }
244 }
245
246 #[unstable(feature = "sgx_platform", issue = "56975")]
247 impl<T> User<T> where T: UserSafe {
248     /// Allocate space for `T` in user memory.
249     pub fn uninitialized() -> Self {
250         Self::new_uninit_bytes(mem::size_of::<T>())
251     }
252 }
253
254 #[unstable(feature = "sgx_platform", issue = "56975")]
255 impl<T> User<[T]> where [T]: UserSafe {
256     /// Allocate space for a `[T]` of `n` elements in user memory.
257     pub fn uninitialized(n: usize) -> Self {
258         Self::new_uninit_bytes(n * mem::size_of::<T>())
259     }
260
261     /// Creates an owned `User<[T]>` from a raw thin pointer and a slice length.
262     ///
263     /// # Safety
264     /// The caller must ensure `ptr` points to `len` elements of `T`, is
265     /// freeable with the `free` usercall and the alignment of `T`, and is
266     /// uniquely owned.
267     ///
268     /// # Panics
269     /// This function panics if:
270     ///
271     /// * The pointer is not aligned
272     /// * The pointer is null
273     /// * The pointed-to range does not fit in the address space
274     /// * The pointed-to range is not in user memory
275     pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
276         User(NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>())))
277     }
278 }
279
280 #[unstable(feature = "sgx_platform", issue = "56975")]
281 impl<T: ?Sized> UserRef<T> where T: UserSafe {
282     /// Creates a `&UserRef<[T]>` from a raw pointer.
283     ///
284     /// # Safety
285     /// The caller must ensure `ptr` points to `T`.
286     ///
287     /// # Panics
288     /// This function panics if:
289     ///
290     /// * The pointer is not aligned
291     /// * The pointer is null
292     /// * The pointed-to range is not in user memory
293     pub unsafe fn from_ptr<'a>(ptr: *const T) -> &'a Self {
294         T::check_ptr(ptr);
295         &*(ptr as *const Self)
296     }
297
298     /// Creates a `&mut UserRef<[T]>` from a raw pointer. See the struct
299     /// documentation for the nuances regarding a `&mut UserRef<T>`.
300     ///
301     /// # Safety
302     /// The caller must ensure `ptr` points to `T`.
303     ///
304     /// # Panics
305     /// This function panics if:
306     ///
307     /// * The pointer is not aligned
308     /// * The pointer is null
309     /// * The pointed-to range is not in user memory
310     pub unsafe fn from_mut_ptr<'a>(ptr: *mut T) -> &'a mut Self {
311         T::check_ptr(ptr);
312         &mut*(ptr as *mut Self)
313     }
314
315     /// Copies `val` into user memory.
316     ///
317     /// # Panics
318     /// This function panics if the destination doesn't have the same size as
319     /// the source. This can happen for dynamically-sized types such as slices.
320     pub fn copy_from_enclave(&mut self, val: &T) {
321         unsafe {
322             assert_eq!(mem::size_of_val(val), mem::size_of_val( &*self.0.get() ));
323             ptr::copy(
324                 val as *const T as *const u8,
325                 self.0.get() as *mut T as *mut u8,
326                 mem::size_of_val(val)
327             );
328         }
329     }
330
331     /// Copies the value from user memory and place it into `dest`.
332     ///
333     /// # Panics
334     /// This function panics if the destination doesn't have the same size as
335     /// the source. This can happen for dynamically-sized types such as slices.
336     pub fn copy_to_enclave(&self, dest: &mut T) {
337         unsafe {
338             assert_eq!(mem::size_of_val(dest), mem::size_of_val( &*self.0.get() ));
339             ptr::copy(
340                 self.0.get() as *const T as *const u8,
341                 dest as *mut T as *mut u8,
342                 mem::size_of_val(dest)
343             );
344         }
345     }
346
347     /// Obtain a raw pointer from this reference.
348     pub fn as_raw_ptr(&self) -> *const T {
349         self as *const _ as _
350     }
351
352     /// Obtain a raw pointer from this reference.
353     pub fn as_raw_mut_ptr(&mut self) -> *mut T {
354         self as *mut _ as _
355     }
356 }
357
358 #[unstable(feature = "sgx_platform", issue = "56975")]
359 impl<T> UserRef<T> where T: UserSafe {
360     /// Copies the value from user memory into enclave memory.
361     pub fn to_enclave(&self) -> T {
362         unsafe { ptr::read(self.0.get()) }
363     }
364 }
365
366 #[unstable(feature = "sgx_platform", issue = "56975")]
367 impl<T> UserRef<[T]> where [T]: UserSafe {
368     /// Creates a `&UserRef<[T]>` from a raw thin pointer and a slice length.
369     ///
370     /// # Safety
371     /// The caller must ensure `ptr` points to `n` elements of `T`.
372     ///
373     /// # Panics
374     /// This function panics if:
375     ///
376     /// * The pointer is not aligned
377     /// * The pointer is null
378     /// * The pointed-to range does not fit in the address space
379     /// * The pointed-to range is not in user memory
380     pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
381         &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self)
382     }
383
384     /// Creates a `&mut UserRef<[T]>` from a raw thin pointer and a slice length.
385     /// See the struct documentation for the nuances regarding a
386     /// `&mut UserRef<T>`.
387     ///
388     /// # Safety
389     /// The caller must ensure `ptr` points to `n` elements of `T`.
390     ///
391     /// # Panics
392     /// This function panics if:
393     ///
394     /// * The pointer is not aligned
395     /// * The pointer is null
396     /// * The pointed-to range does not fit in the address space
397     /// * The pointed-to range is not in user memory
398     pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self {
399         &mut*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self)
400     }
401
402     /// Obtain a raw pointer to the first element of this user slice.
403     pub fn as_ptr(&self) -> *const T {
404         self.0.get() as _
405     }
406
407     /// Obtain a raw pointer to the first element of this user slice.
408     pub fn as_mut_ptr(&mut self) -> *mut T {
409         self.0.get() as _
410     }
411
412     /// Obtain the number of elements in this user slice.
413     pub fn len(&self) -> usize {
414         unsafe { (*self.0.get()).len() }
415     }
416
417     /// Copies the value from user memory and place it into `dest`. Afterwards,
418     /// `dest` will contain exactly `self.len()` elements.
419     ///
420     /// # Panics
421     /// This function panics if the destination doesn't have the same size as
422     /// the source. This can happen for dynamically-sized types such as slices.
423     pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) {
424         unsafe {
425             if let Some(missing) = self.len().checked_sub(dest.capacity()) {
426                 dest.reserve(missing)
427             }
428             dest.set_len(self.len());
429             self.copy_to_enclave(&mut dest[..]);
430         }
431     }
432
433     /// Copies the value from user memory into a vector in enclave memory.
434     pub fn to_enclave(&self) -> Vec<T> {
435         let mut ret = Vec::with_capacity(self.len());
436         self.copy_to_enclave_vec(&mut ret);
437         ret
438     }
439
440     /// Returns an iterator over the slice.
441     pub fn iter(&self) -> Iter<'_, T>
442         where T: UserSafe // FIXME: should be implied by [T]: UserSafe?
443     {
444         unsafe {
445             Iter((&*self.as_raw_ptr()).iter())
446         }
447     }
448
449     /// Returns an iterator that allows modifying each value.
450     pub fn iter_mut(&mut self) -> IterMut<'_, T>
451         where T: UserSafe // FIXME: should be implied by [T]: UserSafe?
452     {
453         unsafe {
454             IterMut((&mut*self.as_raw_mut_ptr()).iter_mut())
455         }
456     }
457 }
458
459 /// Immutable user slice iterator
460 ///
461 /// This struct is created by the `iter` method on `UserRef<[T]>`.
462 #[unstable(feature = "sgx_platform", issue = "56975")]
463 pub struct Iter<'a, T: 'a + UserSafe>(slice::Iter<'a, T>);
464
465 #[unstable(feature = "sgx_platform", issue = "56975")]
466 impl<'a, T: UserSafe> Iterator for Iter<'a, T> {
467     type Item = &'a UserRef<T>;
468
469     #[inline]
470     fn next(&mut self) -> Option<Self::Item> {
471         unsafe {
472             self.0.next().map(|e| UserRef::from_ptr(e))
473         }
474     }
475 }
476
477 /// Mutable user slice iterator
478 ///
479 /// This struct is created by the `iter_mut` method on `UserRef<[T]>`.
480 #[unstable(feature = "sgx_platform", issue = "56975")]
481 pub struct IterMut<'a, T: 'a + UserSafe>(slice::IterMut<'a, T>);
482
483 #[unstable(feature = "sgx_platform", issue = "56975")]
484 impl<'a, T: UserSafe> Iterator for IterMut<'a, T> {
485     type Item = &'a mut UserRef<T>;
486
487     #[inline]
488     fn next(&mut self) -> Option<Self::Item> {
489         unsafe {
490             self.0.next().map(|e| UserRef::from_mut_ptr(e))
491         }
492     }
493 }
494
495 #[unstable(feature = "sgx_platform", issue = "56975")]
496 impl<T: ?Sized> Deref for User<T> where T: UserSafe {
497     type Target = UserRef<T>;
498
499     fn deref(&self) -> &Self::Target {
500         unsafe { &*self.0.as_ptr() }
501     }
502 }
503
504 #[unstable(feature = "sgx_platform", issue = "56975")]
505 impl<T: ?Sized> DerefMut for User<T> where T: UserSafe {
506     fn deref_mut(&mut self) -> &mut Self::Target {
507         unsafe { &mut*self.0.as_ptr() }
508     }
509 }
510
511 #[unstable(feature = "sgx_platform", issue = "56975")]
512 impl<T: ?Sized> Drop for User<T> where T: UserSafe {
513     fn drop(&mut self) {
514         unsafe {
515             let ptr = (*self.0.as_ptr()).0.get();
516             super::free(ptr as _, mem::size_of_val(&mut*ptr), T::align_of());
517         }
518     }
519 }
520
521 #[unstable(feature = "sgx_platform", issue = "56975")]
522 impl<T: CoerceUnsized<U>, U> CoerceUnsized<UserRef<U>> for UserRef<T> {}
523
524 #[unstable(feature = "sgx_platform", issue = "56975")]
525 impl<T, I: SliceIndex<[T]>> Index<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
526     type Output = UserRef<I::Output>;
527
528     #[inline]
529     fn index(&self, index: I) -> &UserRef<I::Output> {
530         unsafe {
531             if let Some(slice) = index.get(&*self.as_raw_ptr()) {
532                 UserRef::from_ptr(slice)
533             } else {
534                 rtabort!("index out of range for user slice");
535             }
536         }
537     }
538 }
539
540 #[unstable(feature = "sgx_platform", issue = "56975")]
541 impl<T, I: SliceIndex<[T]>> IndexMut<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
542     #[inline]
543     fn index_mut(&mut self, index: I) -> &mut UserRef<I::Output> {
544         unsafe {
545             if let Some(slice) = index.get_mut(&mut*self.as_raw_mut_ptr()) {
546                 UserRef::from_mut_ptr(slice)
547             } else {
548                 rtabort!("index out of range for user slice");
549             }
550         }
551     }
552 }
553
554 #[unstable(feature = "sgx_platform", issue = "56975")]
555 impl UserRef<super::raw::ByteBuffer> {
556     /// Copies the user memory range pointed to by the user `ByteBuffer` to
557     /// enclave memory.
558     ///
559     /// # Panics
560     /// This function panics if, in the user `ByteBuffer`:
561     ///
562     /// * The pointer is null
563     /// * The pointed-to range does not fit in the address space
564     /// * The pointed-to range is not in user memory
565     pub fn copy_user_buffer(&self) -> Vec<u8> {
566         unsafe {
567             let buf = self.to_enclave();
568             if buf.len > 0 {
569                 User::from_raw_parts(buf.data as _, buf.len).to_enclave()
570             } else {
571                 // Mustn't look at `data` or call `free` if `len` is `0`.
572                 Vec::with_capacity(0)
573             }
574         }
575     }
576 }