X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibstd%2Fsys%2Fsgx%2Fabi%2Fusercalls%2Fmod.rs;h=ae803ee47a6cb1717bd7439a6cc80322b28557ad;hb=c34fbfaad38cf5829ef5cfe780dc9d58480adeaa;hp=0abfc26bced0025d4188ef341c8302d773295e9e;hpb=b13291f6a73b8b439dfbf215cf9a84053efedd4a;p=rust.git diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs index 0abfc26bced..ae803ee47a6 100644 --- a/src/libstd/sys/sgx/abi/usercalls/mod.rs +++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs @@ -1,4 +1,5 @@ -use crate::io::{Error as IoError, Result as IoResult}; +use crate::cmp; +use crate::io::{Error as IoError, IoSlice, IoSliceMut, Result as IoResult}; use crate::time::Duration; pub(crate) mod alloc; @@ -8,13 +9,27 @@ use self::raw::*; /// Usercall `read`. See the ABI documentation for more information. +/// +/// This will do a single `read` usercall and scatter the read data among +/// `bufs`. To read to a single buffer, just pass a slice of length one. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult { +pub fn read(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> IoResult { unsafe { - let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.len()); - let len = raw::read(fd, userbuf.as_mut_ptr(), userbuf.len()).from_sgx_result()?; - userbuf[..len].copy_to_enclave(&mut buf[..len]); - Ok(len) + let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len())); + let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len); + let ret_len = raw::read(fd, userbuf.as_mut_ptr(), userbuf.len()).from_sgx_result()?; + let userbuf = &userbuf[..ret_len]; + let mut index = 0; + for buf in bufs { + let end = cmp::min(index + buf.len(), userbuf.len()); + if let Some(buflen) = end.checked_sub(index) { + userbuf[index..end].copy_to_enclave(&mut buf[..buflen]); + index += buf.len(); + } else { + break; + } + } + Ok(userbuf.len()) } } @@ -30,10 +45,24 @@ pub fn read_alloc(fd: Fd) -> IoResult> { } /// Usercall `write`. See the ABI documentation for more information. +/// +/// This will do a single `write` usercall and gather the written data from +/// `bufs`. To write from a single buffer, just pass a slice of length one. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn write(fd: Fd, buf: &[u8]) -> IoResult { +pub fn write(fd: Fd, bufs: &[IoSlice<'_>]) -> IoResult { unsafe { - let userbuf = alloc::User::new_from_enclave(buf); + let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len())); + let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len); + let mut index = 0; + for buf in bufs { + let end = cmp::min(index + buf.len(), userbuf.len()); + if let Some(buflen) = end.checked_sub(index) { + userbuf[index..end].copy_from_enclave(&buf[..buflen]); + index += buf.len(); + } else { + break; + } + } raw::write(fd, userbuf.as_ptr(), userbuf.len()).from_sgx_result() } } @@ -61,11 +90,8 @@ pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> { unsafe { let addr_user = alloc::User::new_from_enclave(addr.as_bytes()); let mut local = alloc::User::::uninitialized(); - let fd = raw::bind_stream( - addr_user.as_ptr(), - addr_user.len(), - local.as_raw_mut_ptr() - ).from_sgx_result()?; + let fd = raw::bind_stream(addr_user.as_ptr(), addr_user.len(), local.as_raw_mut_ptr()) + .from_sgx_result()?; let local = string_from_bytebuffer(&local, "bind_stream", "local_addr"); Ok((fd, local)) } @@ -77,13 +103,10 @@ pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> { unsafe { let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized(); let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done - // without forcing coercion? + // without forcing coercion? let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap()); - let fd = raw::accept_stream( - fd, - local.as_raw_mut_ptr(), - peer.as_raw_mut_ptr() - ).from_sgx_result()?; + let fd = raw::accept_stream(fd, local.as_raw_mut_ptr(), peer.as_raw_mut_ptr()) + .from_sgx_result()?; let local = string_from_bytebuffer(&local, "accept_stream", "local_addr"); let peer = string_from_bytebuffer(&peer, "accept_stream", "peer_addr"); Ok((fd, local, peer)) @@ -97,14 +120,15 @@ pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> { let addr_user = alloc::User::new_from_enclave(addr.as_bytes()); let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized(); let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done - // without forcing coercion? + // without forcing coercion? let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap()); let fd = raw::connect_stream( addr_user.as_ptr(), addr_user.len(), local.as_raw_mut_ptr(), - peer.as_raw_mut_ptr() - ).from_sgx_result()?; + peer.as_raw_mut_ptr(), + ) + .from_sgx_result()?; let local = string_from_bytebuffer(&local, "connect_stream", "local_addr"); let peer = string_from_bytebuffer(&peer, "connect_stream", "peer_addr"); Ok((fd, local, peer)) @@ -154,25 +178,25 @@ pub fn alloc(size: usize, alignment: usize) -> IoResult<*mut u8> { fn check_os_error(err: Result) -> i32 { // FIXME: not sure how to make sure all variants of Error are covered - if err == Error::NotFound as _ || - err == Error::PermissionDenied as _ || - err == Error::ConnectionRefused as _ || - err == Error::ConnectionReset as _ || - err == Error::ConnectionAborted as _ || - err == Error::NotConnected as _ || - err == Error::AddrInUse as _ || - err == Error::AddrNotAvailable as _ || - err == Error::BrokenPipe as _ || - err == Error::AlreadyExists as _ || - err == Error::WouldBlock as _ || - err == Error::InvalidInput as _ || - err == Error::InvalidData as _ || - err == Error::TimedOut as _ || - err == Error::WriteZero as _ || - err == Error::Interrupted as _ || - err == Error::Other as _ || - err == Error::UnexpectedEof as _ || - ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&err) + if err == Error::NotFound as _ + || err == Error::PermissionDenied as _ + || err == Error::ConnectionRefused as _ + || err == Error::ConnectionReset as _ + || err == Error::ConnectionAborted as _ + || err == Error::NotConnected as _ + || err == Error::AddrInUse as _ + || err == Error::AddrNotAvailable as _ + || err == Error::BrokenPipe as _ + || err == Error::AlreadyExists as _ + || err == Error::WouldBlock as _ + || err == Error::InvalidInput as _ + || err == Error::InvalidData as _ + || err == Error::TimedOut as _ + || err == Error::WriteZero as _ + || err == Error::Interrupted as _ + || err == Error::Other as _ + || err == Error::UnexpectedEof as _ + || ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&err) { err } else {