Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement read_buf and vectored read/write for SGX stdio #137355

Merged
merged 3 commits into from
Mar 13, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 48 additions & 16 deletions library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ use super::super::mem::{is_enclave_range, is_user_range};
use crate::arch::asm;
use crate::cell::UnsafeCell;
use crate::convert::TryInto;
use crate::mem::{self, ManuallyDrop};
use crate::mem::{self, ManuallyDrop, MaybeUninit};
use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut};
use crate::pin::PinCoerceUnsized;
use crate::ptr::{self, NonNull};
@@ -209,6 +209,45 @@ impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> {
}
}

/// A type which can a destination for safely copying from userspace.
///
/// # Safety
///
/// Requires that `T` and `Self` have identical layouts.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub unsafe trait UserSafeCopyDestination<T: ?Sized> {
/// Returns a pointer for writing to the value.
fn as_mut_ptr(&mut self) -> *mut T;
}

#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T> UserSafeCopyDestination<T> for T {
fn as_mut_ptr(&mut self) -> *mut T {
self as _
}
}

#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T> UserSafeCopyDestination<[T]> for [T] {
fn as_mut_ptr(&mut self) -> *mut [T] {
self as _
}
}

#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T> UserSafeCopyDestination<T> for MaybeUninit<T> {
fn as_mut_ptr(&mut self) -> *mut T {
self as *mut Self as _
}
}

#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T> UserSafeCopyDestination<[T]> for [MaybeUninit<T>] {
fn as_mut_ptr(&mut self) -> *mut [T] {
self as *mut Self as _
}
}

#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> User<T>
where
@@ -544,12 +583,12 @@ where
/// # 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(&self, dest: &mut T) {
pub fn copy_to_enclave<U: ?Sized + UserSafeCopyDestination<T>>(&self, dest: &mut U) {
unsafe {
assert_eq!(size_of_val(dest), 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,
dest.as_mut_ptr() as *mut u8,
size_of_val(dest),
);
}
@@ -639,25 +678,18 @@ where
unsafe { (*self.0.get()).len() }
}

/// Copies 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>) {
if let Some(missing) = self.len().checked_sub(dest.capacity()) {
dest.reserve(missing)
}
/// Copies the value from user memory and appends it to `dest`.
pub fn append_to_enclave_vec(&self, dest: &mut Vec<T>) {
dest.reserve(self.len());
self.copy_to_enclave(&mut dest.spare_capacity_mut()[..self.len()]);
// SAFETY: We reserve enough space above.
unsafe { dest.set_len(self.len()) };
self.copy_to_enclave(&mut dest[..]);
unsafe { dest.set_len(dest.len() + self.len()) };
}

/// Copies 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);
self.append_to_enclave_vec(&mut ret);
ret
}

17 changes: 16 additions & 1 deletion library/std/src/sys/pal/sgx/abi/usercalls/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::cmp;
use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult};
use crate::io::{
BorrowedCursor, Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult,
};
use crate::random::{DefaultRandomSource, Random};
use crate::time::{Duration, Instant};

@@ -36,6 +38,19 @@ pub fn read(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> IoResult<usize> {
}
}

/// Usercall `read` with an uninitialized buffer. See the ABI documentation for
/// more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn read_buf(fd: Fd, mut buf: BorrowedCursor<'_>) -> IoResult<()> {
unsafe {
let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.capacity());
let len = raw::read(fd, userbuf.as_mut_ptr().cast(), userbuf.len()).from_sgx_result()?;
userbuf[..len].copy_to_enclave(&mut buf.as_mut()[..len]);
buf.advance_unchecked(len);
Ok(())
}
}

/// Usercall `read_alloc`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn read_alloc(fd: Fd) -> IoResult<Vec<u8>> {
2 changes: 1 addition & 1 deletion library/std/src/sys/pal/sgx/fd.rs
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ impl FileDesc {
}

pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
crate::io::default_read_buf(|b| self.read(b), buf)
usercalls::read_buf(self.fd, buf)
}

pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
33 changes: 32 additions & 1 deletion library/std/src/sys/stdio/sgx.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use fortanix_sgx_abi as abi;

use crate::io;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::sys::fd::FileDesc;

pub struct Stdin(());
@@ -24,6 +24,19 @@ impl io::Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
with_std_fd(abi::FD_STDIN, |fd| fd.read(buf))
}

fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
with_std_fd(abi::FD_STDIN, |fd| fd.read_buf(buf))
}

fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
with_std_fd(abi::FD_STDIN, |fd| fd.read_vectored(bufs))
}

#[inline]
fn is_read_vectored(&self) -> bool {
true
}
}

impl Stdout {
@@ -40,6 +53,15 @@ impl io::Write for Stdout {
fn flush(&mut self) -> io::Result<()> {
with_std_fd(abi::FD_STDOUT, |fd| fd.flush())
}

fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
with_std_fd(abi::FD_STDOUT, |fd| fd.write_vectored(bufs))
}

#[inline]
fn is_write_vectored(&self) -> bool {
true
}
}

impl Stderr {
@@ -56,6 +78,15 @@ impl io::Write for Stderr {
fn flush(&mut self) -> io::Result<()> {
with_std_fd(abi::FD_STDERR, |fd| fd.flush())
}

fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
with_std_fd(abi::FD_STDERR, |fd| fd.write_vectored(bufs))
}

#[inline]
fn is_write_vectored(&self) -> bool {
true
}
}

pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE;