]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/sgx/abi/usercalls/mod.rs
d1d180e48251f90fcae1d1feeee1f957e03c3220
[rust.git] / src / libstd / sys / sgx / abi / usercalls / mod.rs
1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 pub use fortanix_sgx_abi::*;
12
13 use io::{Error as IoError, Result as IoResult};
14 use time::Duration;
15
16 pub mod alloc;
17 #[macro_use]
18 mod raw;
19
20 pub(crate) fn copy_user_buffer(buf: &alloc::UserRef<ByteBuffer>) -> Vec<u8> {
21     unsafe {
22         let buf = buf.to_enclave();
23         alloc::User::from_raw_parts(buf.data as _, buf.len).to_enclave()
24     }
25 }
26
27 pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult<usize> {
28     unsafe {
29         let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.len());
30         let len = raw::read(fd, userbuf.as_mut_ptr(), userbuf.len()).from_sgx_result()?;
31         userbuf[..len].copy_to_enclave(&mut buf[..len]);
32         Ok(len)
33     }
34 }
35
36 pub fn write(fd: Fd, buf: &[u8]) -> IoResult<usize> {
37     unsafe {
38         let userbuf = alloc::User::new_from_enclave(buf);
39         raw::write(fd, userbuf.as_ptr(), userbuf.len()).from_sgx_result()
40     }
41 }
42
43 pub fn flush(fd: Fd) -> IoResult<()> {
44     unsafe { raw::flush(fd).from_sgx_result() }
45 }
46
47 pub fn close(fd: Fd) {
48     unsafe { raw::close(fd) }
49 }
50
51 fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
52     String::from_utf8(copy_user_buffer(buf))
53         .unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
54 }
55
56 pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> {
57     unsafe {
58         let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
59         let mut local = alloc::User::<ByteBuffer>::uninitialized();
60         let fd = raw::bind_stream(
61             addr_user.as_ptr(),
62             addr_user.len(),
63             local.as_raw_mut_ptr()
64         ).from_sgx_result()?;
65         let local = string_from_bytebuffer(&local, "bind_stream", "local_addr");
66         Ok((fd, local))
67     }
68 }
69
70 pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> {
71     unsafe {
72         let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
73         let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
74                                                                // without forcing coercion?
75         let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
76         let fd = raw::accept_stream(
77             fd,
78             local.as_raw_mut_ptr(),
79             peer.as_raw_mut_ptr()
80         ).from_sgx_result()?;
81         let local = string_from_bytebuffer(&local, "accept_stream", "local_addr");
82         let peer = string_from_bytebuffer(&peer, "accept_stream", "peer_addr");
83         Ok((fd, local, peer))
84     }
85 }
86
87 pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> {
88     unsafe {
89         let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
90         let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
91         let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
92                                                                // without forcing coercion?
93         let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
94         let fd = raw::connect_stream(
95             addr_user.as_ptr(),
96             addr_user.len(),
97             local.as_raw_mut_ptr(),
98             peer.as_raw_mut_ptr()
99         ).from_sgx_result()?;
100         let local = string_from_bytebuffer(&local, "connect_stream", "local_addr");
101         let peer = string_from_bytebuffer(&peer, "connect_stream", "peer_addr");
102         Ok((fd, local, peer))
103     }
104 }
105
106 pub fn launch_thread() -> IoResult<()> {
107     unsafe { raw::launch_thread().from_sgx_result() }
108 }
109
110 pub fn exit(panic: bool) -> ! {
111     unsafe { raw::exit(panic) }
112 }
113
114 pub fn wait(event_mask: u64, timeout: u64) -> IoResult<u64> {
115     unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
116 }
117
118 pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
119     unsafe { raw::send(event_set, tcs).from_sgx_result() }
120 }
121
122 pub fn insecure_time() -> Duration {
123     let t = unsafe { raw::insecure_time() };
124     Duration::new(t / 1_000_000_000, (t % 1_000_000_000) as _)
125 }
126
127 pub fn alloc(size: usize, alignment: usize) -> IoResult<*mut u8> {
128     unsafe { raw::alloc(size, alignment).from_sgx_result() }
129 }
130
131 pub use self::raw::free;
132
133 fn check_os_error(err: Result) -> i32 {
134     // FIXME: not sure how to make sure all variants of Error are covered
135     if err == Error::NotFound as _ ||
136        err == Error::PermissionDenied as _ ||
137        err == Error::ConnectionRefused as _ ||
138        err == Error::ConnectionReset as _ ||
139        err == Error::ConnectionAborted as _ ||
140        err == Error::NotConnected as _ ||
141        err == Error::AddrInUse as _ ||
142        err == Error::AddrNotAvailable as _ ||
143        err == Error::BrokenPipe as _ ||
144        err == Error::AlreadyExists as _ ||
145        err == Error::WouldBlock as _ ||
146        err == Error::InvalidInput as _ ||
147        err == Error::InvalidData as _ ||
148        err == Error::TimedOut as _ ||
149        err == Error::WriteZero as _ ||
150        err == Error::Interrupted as _ ||
151        err == Error::Other as _ ||
152        err == Error::UnexpectedEof as _ ||
153        ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&err)
154     {
155         err
156     } else {
157         panic!("Usercall: returned invalid error value {}", err)
158     }
159 }
160
161 trait FromSgxResult {
162     type Return;
163
164     fn from_sgx_result(self) -> IoResult<Self::Return>;
165 }
166
167 impl<T> FromSgxResult for (Result, T) {
168     type Return = T;
169
170     fn from_sgx_result(self) -> IoResult<Self::Return> {
171         if self.0 == RESULT_SUCCESS {
172             Ok(self.1)
173         } else {
174             Err(IoError::from_raw_os_error(check_os_error(self.0)))
175         }
176     }
177 }
178
179 impl FromSgxResult for Result {
180     type Return = ();
181
182     fn from_sgx_result(self) -> IoResult<Self::Return> {
183         if self == RESULT_SUCCESS {
184             Ok(())
185         } else {
186             Err(IoError::from_raw_os_error(check_os_error(self)))
187         }
188     }
189 }