sallyport/guest/
handler.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use super::alloc::{Alloc, Allocator, Collect, Commit, Committer};
4use super::call::kind;
5use super::syscall::types::{MremapFlags, SockaddrInput, SockaddrOutput, SockoptInput};
6use super::{enarxcall, gdbcall, syscall, Call, Platform, ThreadLocalStorage, SIGRTMAX};
7use crate::item::enarxcall::sgx;
8use crate::item::syscall::sigaction;
9use crate::libc::{
10    clockid_t, epoll_event, gid_t, mode_t, off_t, pid_t, pollfd, sigset_t, stack_t, stat, timespec,
11    uid_t, utsname, Ioctl, SYS_accept, SYS_accept4, SYS_arch_prctl, SYS_bind, SYS_brk,
12    SYS_clock_getres, SYS_clock_gettime, SYS_close, SYS_connect, SYS_dup, SYS_dup2, SYS_dup3,
13    SYS_epoll_create1, SYS_epoll_ctl, SYS_epoll_pwait, SYS_epoll_wait, SYS_eventfd2, SYS_exit,
14    SYS_exit_group, SYS_fcntl, SYS_fstat, SYS_getegid, SYS_geteuid, SYS_getgid, SYS_getpid,
15    SYS_getrandom, SYS_getsockname, SYS_getuid, SYS_ioctl, SYS_listen, SYS_madvise, SYS_mmap,
16    SYS_mprotect, SYS_mremap, SYS_munmap, SYS_nanosleep, SYS_open, SYS_poll, SYS_read,
17    SYS_readlink, SYS_readv, SYS_recvfrom, SYS_rt_sigaction, SYS_rt_sigprocmask, SYS_sendto,
18    SYS_set_tid_address, SYS_setsockopt, SYS_sigaltstack, SYS_socket, SYS_sync, SYS_uname,
19    SYS_write, SYS_writev, EFAULT, EINVAL, ENOSYS, ENOTSUP, FIONBIO, FIONREAD, MAP_ANONYMOUS,
20    MAP_PRIVATE, MREMAP_DONTUNMAP, MREMAP_FIXED, MREMAP_MAYMOVE, PROT_EXEC, PROT_READ, PROT_WRITE,
21};
22use crate::{item, Result};
23
24use core::arch::x86_64::CpuidResult;
25use core::ffi::{c_int, c_size_t, c_uint, c_ulong, c_void};
26use core::mem::size_of;
27use core::ptr::NonNull;
28use core::slice;
29
30/// Guest request handler.
31pub trait Handler {
32    /// Suspend guest execution and pass control to host.
33    /// This function will return when the host passes control back to the guest.
34    fn sally(&mut self) -> Result<()>;
35
36    /// Returns an immutable borrow of the sallyport block.
37    fn block(&self) -> &[usize];
38
39    /// Returns a mutable borrow of the sallyport block.
40    fn block_mut(&mut self) -> &mut [usize];
41
42    /// Returns a mutable borrow of shared [ThreadLocalStorage].
43    fn thread_local_storage(&mut self) -> &mut ThreadLocalStorage;
44
45    /// Executes an arbitrary call.
46    /// Examples of calls that this method can execute are:
47    /// - [`syscall::Exit`]
48    /// - [`syscall::Read`]
49    /// - [`syscall::Write`]
50    /// - [`gdbcall::Read`]
51    /// - [`gdbcall::Write`]
52    #[inline]
53    fn execute<'a, K: kind::Kind, T: Call<'a, K>>(&mut self, call: T) -> Result<T::Collected> {
54        let mut alloc = Alloc::new(self.block_mut()).stage();
55        let ((call, len), mut end_ref) =
56            alloc.reserve_input(|alloc| alloc.section(|alloc| call.stage(alloc)))?;
57
58        let alloc = alloc.commit();
59        let call = call.commit(&alloc);
60        let alloc = if len > 0 {
61            end_ref.copy_from(
62                &alloc,
63                item::Header {
64                    kind: item::Kind::End,
65                    size: 0,
66                },
67            );
68            let collect = alloc.sally();
69            self.sally()?;
70            collect(self.block())?
71        } else {
72            alloc.collect()
73        };
74        Ok(call.collect(&alloc))
75    }
76
77    /// Loops infinitely trying to exit.
78    #[inline]
79    fn attacked(&mut self) -> ! {
80        loop {
81            let _ = self.exit(1);
82        }
83    }
84
85    // Syscalls, sorted alphabetically.
86
87    /// Executes [`accept`](https://man7.org/linux/man-pages/man2/accept.2.html) syscall akin to [`libc::accept`].
88    #[inline]
89    fn accept<'a>(
90        &mut self,
91        sockfd: c_int,
92        addr: Option<impl Into<SockaddrOutput<'a>>>,
93    ) -> Result<c_int> {
94        self.execute(syscall::Accept { sockfd, addr })?
95    }
96
97    /// Executes [`accept4`](https://man7.org/linux/man-pages/man2/accept4.2.html) syscall akin to [`libc::accept4`].
98    #[inline]
99    fn accept4<'a>(
100        &mut self,
101        sockfd: c_int,
102        addr: Option<impl Into<SockaddrOutput<'a>>>,
103        flags: c_int,
104    ) -> Result<c_int> {
105        self.execute(syscall::Accept4 {
106            sockfd,
107            addr,
108            flags,
109        })?
110    }
111
112    /// Executes [`arch_prctl`](https://man7.org/linux/man-pages/man2/arch_prctl.2.html).
113    fn arch_prctl(&mut self, platform: &impl Platform, code: c_int, addr: c_ulong) -> Result<()>;
114
115    /// Executes [`bind`](https://man7.org/linux/man-pages/man2/bind.2.html) syscall akin to [`libc::bind`].
116    #[inline]
117    fn bind<'a>(&mut self, sockfd: c_int, addr: impl Into<SockaddrInput<'a>>) -> Result<()> {
118        self.execute(syscall::Bind { sockfd, addr })?
119    }
120
121    /// Executes [`brk`](https://man7.org/linux/man-pages/man2/brk.2.html) syscall akin to [`libc::brk`].
122    fn brk(
123        &mut self,
124        platform: &impl Platform,
125        addr: Option<NonNull<c_void>>,
126    ) -> Result<NonNull<c_void>>;
127
128    /// Executes [`clock_getres`](https://man7.org/linux/man-pages/man2/clock_getres.2.html) syscall akin to [`libc::clock_getres`].
129    #[inline]
130    fn clock_getres(&mut self, clockid: clockid_t, res: Option<&mut timespec>) -> Result<()> {
131        self.execute(syscall::ClockGetres { clockid, res })?
132    }
133
134    /// Executes [`clock_gettime`](https://man7.org/linux/man-pages/man2/clock_gettime.2.html) syscall akin to [`libc::clock_gettime`].
135    #[inline]
136    fn clock_gettime(&mut self, clockid: clockid_t, tp: &mut timespec) -> Result<()> {
137        self.execute(syscall::ClockGettime { clockid, tp })?
138    }
139
140    /// Executes [`close`](https://man7.org/linux/man-pages/man2/close.2.html) syscall akin to [`libc::close`].
141    #[inline]
142    fn close(&mut self, fd: c_int) -> Result<()> {
143        self.execute(syscall::Close { fd })?
144    }
145
146    /// Executes [`connect`](https://man7.org/linux/man-pages/man2/connect.2.html) syscall akin to [`libc::connect`].
147    #[inline]
148    fn connect<'a>(&mut self, sockfd: c_int, addr: impl Into<SockaddrInput<'a>>) -> Result<()> {
149        self.execute(syscall::Connect { sockfd, addr })?
150    }
151
152    /// Executes [`dup`](https://man7.org/linux/man-pages/man2/dup.2.html) syscall akin to [`libc::dup`].
153    #[inline]
154    fn dup(&mut self, oldfd: c_int) -> Result<()> {
155        self.execute(syscall::Dup { oldfd })?
156    }
157
158    /// Executes [`dup2`](https://man7.org/linux/man-pages/man2/dup2.2.html) syscall akin to [`libc::dup2`].
159    #[inline]
160    fn dup2(&mut self, oldfd: c_int, newfd: c_int) -> Result<()> {
161        self.execute(syscall::Dup2 { oldfd, newfd })?
162    }
163
164    /// Executes [`dup3`](https://man7.org/linux/man-pages/man2/dup3.2.html) syscall akin to [`libc::dup3`].
165    #[inline]
166    fn dup3(&mut self, oldfd: c_int, newfd: c_int, flags: c_int) -> Result<()> {
167        self.execute(syscall::Dup3 {
168            oldfd,
169            newfd,
170            flags,
171        })?
172    }
173
174    /// Executes [`epoll_create1`](https://man7.org/linux/man-pages/man2/epoll_create1.2.html) syscall akin to [`libc::epoll_create1`].
175    #[inline]
176    fn epoll_create1(&mut self, flags: c_int) -> Result<c_int> {
177        self.execute(syscall::EpollCreate1 { flags })?
178    }
179
180    /// Executes [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) syscall akin to [`libc::epoll_ctl`].
181    #[inline]
182    fn epoll_ctl(&mut self, epfd: c_int, op: c_int, fd: c_int, event: &epoll_event) -> Result<()> {
183        self.execute(syscall::EpollCtl {
184            epfd,
185            op,
186            fd,
187            event,
188        })?
189    }
190
191    /// Executes [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html) syscall akin to [`libc::epoll_wait`].
192    #[inline]
193    fn epoll_wait(
194        &mut self,
195        epfd: c_int,
196        events: &mut [epoll_event],
197        timeout: c_int,
198    ) -> Result<c_int> {
199        self.execute(syscall::EpollWait {
200            epfd,
201            events,
202            timeout,
203        })?
204        .unwrap_or_else(|| self.attacked())
205    }
206
207    /// Executes [`epoll_pwait`](https://man7.org/linux/man-pages/man2/epoll_pwait.2.html) syscall akin to [`libc::epoll_pwait`].
208    #[inline]
209    fn epoll_pwait(
210        &mut self,
211        epfd: c_int,
212        events: &mut [epoll_event],
213        timeout: c_int,
214        sigmask: &sigset_t,
215    ) -> Result<c_int> {
216        self.execute(syscall::EpollPwait {
217            epfd,
218            events,
219            timeout,
220            sigmask,
221        })?
222        .unwrap_or_else(|| self.attacked())
223    }
224
225    /// Executes [`eventfd2`](https://man7.org/linux/man-pages/man2/eventfd2.2.html).
226    #[inline]
227    fn eventfd2(&mut self, initval: c_int, flags: c_int) -> Result<c_int> {
228        self.execute(syscall::Eventfd2 { initval, flags })?
229    }
230
231    /// Executes [`exit`](https://man7.org/linux/man-pages/man2/exit.2.html) syscall akin to [`libc::exit`].
232    #[inline]
233    fn exit(&mut self, status: c_int) -> Result<()> {
234        self.execute(syscall::Exit { status })??;
235        self.attacked()
236    }
237
238    /// Executes [`exit_group`](https://man7.org/linux/man-pages/man2/exit_group.2.html).
239    #[inline]
240    fn exit_group(&mut self, status: c_int) -> Result<()> {
241        self.execute(syscall::ExitGroup { status })??;
242        self.attacked()
243    }
244
245    /// Executes [`fcntl`](https://man7.org/linux/man-pages/man2/fcntl.2.html) syscall akin to [`libc::fcntl`].
246    #[inline]
247    fn fcntl(&mut self, fd: c_int, cmd: c_int, arg: c_int) -> Result<c_int> {
248        self.execute(syscall::Fcntl { fd, cmd, arg })?
249    }
250
251    /// Executes [`fstat`](https://man7.org/linux/man-pages/man2/fstat.2.html) syscall akin to [`libc::fstat`].
252    #[inline]
253    fn fstat(&mut self, fd: c_int, statbuf: &mut stat) -> Result<()> {
254        self.execute(syscall::Fstat { fd, statbuf })?
255    }
256
257    /// Executes [`getegid`](https://man7.org/linux/man-pages/man2/getegid.2.html) syscall akin to [`libc::getegid`].
258    #[inline]
259    fn getegid(&mut self) -> Result<gid_t> {
260        self.execute(syscall::Getegid)
261    }
262
263    /// Executes [`geteuid`](https://man7.org/linux/man-pages/man2/geteuid.2.html) syscall akin to [`libc::geteuid`].
264    #[inline]
265    fn geteuid(&mut self) -> Result<uid_t> {
266        self.execute(syscall::Geteuid)
267    }
268
269    /// Executes [`getgid`](https://man7.org/linux/man-pages/man2/getgid.2.html) syscall akin to [`libc::getgid`].
270    #[inline]
271    fn getgid(&mut self) -> Result<gid_t> {
272        self.execute(syscall::Getgid)
273    }
274
275    /// Executes [`getpid`](https://man7.org/linux/man-pages/man2/getpid.2.html) syscall akin to [`libc::getpid`].
276    #[inline]
277    fn getpid(&mut self) -> Result<pid_t> {
278        self.execute(syscall::Getpid)
279    }
280
281    /// Executes [`getrandom`](https://man7.org/linux/man-pages/man2/getrandom.2.html) syscall akin to [`libc::getrandom`].
282    #[inline]
283    fn getrandom(&mut self, buf: &mut [u8], flags: c_uint) -> Result<c_size_t> {
284        self.execute(syscall::Getrandom { buf, flags })?
285    }
286
287    /// Executes [`getsockname`](https://man7.org/linux/man-pages/man2/getsockname.2.html) syscall akin to [`libc::getsockname`].
288    #[inline]
289    fn getsockname<'a>(
290        &mut self,
291        sockfd: c_int,
292        addr: impl Into<SockaddrOutput<'a>>,
293    ) -> Result<()> {
294        self.execute(syscall::Getsockname { sockfd, addr })?
295    }
296
297    /// Executes [`getuid`](https://man7.org/linux/man-pages/man2/getuid.2.html) syscall akin to [`libc::getuid`].
298    #[inline]
299    fn getuid(&mut self) -> Result<uid_t> {
300        self.execute(syscall::Getuid)
301    }
302
303    /// Executes [`ioctl`](https://man7.org/linux/man-pages/man2/ioctl.2.html) syscall akin to [`libc::ioctl`].
304    #[inline]
305    fn ioctl(&mut self, fd: c_int, request: Ioctl, argp: Option<&mut [u8]>) -> Result<c_int> {
306        self.execute(syscall::Ioctl { fd, request, argp })?
307    }
308
309    /// Executes [`listen`](https://man7.org/linux/man-pages/man2/listen.2.html) syscall akin to [`libc::listen`].
310    #[inline]
311    fn listen(&mut self, sockfd: c_int, backlog: c_int) -> Result<()> {
312        self.execute(syscall::Listen { sockfd, backlog })?
313    }
314
315    /// Executes [`madvise`](https://man7.org/linux/man-pages/man2/madvise.2.html) syscall akin to [`libc::madvise`].
316    fn madvise(
317        &mut self,
318        platform: &impl Platform,
319        addr: NonNull<c_void>,
320        length: c_size_t,
321        advice: c_int,
322    ) -> Result<()>;
323
324    /// Executes [`mmap`](https://man7.org/linux/man-pages/man2/mmap.2.html) syscall akin to [`libc::mmap`].
325    #[allow(clippy::too_many_arguments)]
326    fn mmap(
327        &mut self,
328        platform: &impl Platform,
329        addr: Option<NonNull<c_void>>,
330        length: c_size_t,
331        prot: c_int,
332        flags: c_int,
333        fd: c_int,
334        offset: off_t,
335    ) -> Result<NonNull<c_void>>;
336
337    /// Executes [`mprotect`](https://man7.org/linux/man-pages/man2/mprotect.2.html) syscall akin to [`libc::mprotect`].
338    fn mprotect(
339        &mut self,
340        platform: &impl Platform,
341        addr: NonNull<c_void>,
342        len: c_size_t,
343        prot: c_int,
344    ) -> Result<()>;
345
346    /// Executes [`mremap`](https://man7.org/linux/man-pages/man2/mremap.2.html) syscall akin to [`libc::mremap`].
347    /// If `flags` is `Some`, `[libc::MREMAP_MAYMOVE]` is implied.
348    fn mremap(
349        &mut self,
350        platform: &impl Platform,
351        old_address: NonNull<c_void>,
352        old_size: c_size_t,
353        new_size: c_size_t,
354        flags: Option<MremapFlags>,
355    ) -> Result<NonNull<c_void>> {
356        match flags {
357            None | Some(MremapFlags { FIXED: None, .. }) if new_size == old_size => Ok(old_address),
358            Some(MremapFlags {
359                FIXED: None,
360                DONTUNMAP: false,
361            }) if new_size < old_size => {
362                // Make sure old address range is owned by process
363                let source_slice =
364                    platform.validate_slice::<u8>(old_address.as_ptr() as _, old_size)?;
365
366                // simply unmap the tail
367                let addr = &source_slice[new_size] as *const _;
368                // It is not an error if the indicated range does not contain any mapped pages.
369                let _ = self.munmap(
370                    platform,
371                    NonNull::new(addr as *mut c_void).ok_or(EINVAL)?,
372                    old_size.checked_sub(new_size).ok_or(EINVAL)?,
373                );
374                Ok(old_address)
375            }
376            Some(MremapFlags {
377                FIXED: None,
378                DONTUNMAP,
379            }) if new_size > old_size => {
380                // Make sure old address range is owned by process
381                let source_slice =
382                    platform.validate_slice::<u8>(old_address.as_ptr() as _, old_size)?;
383
384                // simply copy the old data to a new location
385                // FIXME: find out the permissions of the old segment
386                let prot = PROT_WRITE | PROT_EXEC | PROT_READ;
387                let new_addr = self.mmap(
388                    platform,
389                    None,
390                    new_size,
391                    prot,
392                    MAP_PRIVATE | MAP_ANONYMOUS,
393                    -1,
394                    0,
395                )?;
396                // SAFETY: we successfully mmap'ed the memory
397                let new_slice =
398                    unsafe { slice::from_raw_parts_mut(new_addr.as_ptr() as *mut u8, new_size) };
399                new_slice[..old_size].copy_from_slice(source_slice);
400
401                if !DONTUNMAP {
402                    // It is not an error if the indicated range does not contain any mapped pages.
403                    let _ = self.munmap(platform, old_address, old_size);
404                }
405
406                Ok(NonNull::new(new_slice.as_ptr() as *mut _).unwrap())
407            }
408            _ => Err(ENOTSUP),
409        }
410    }
411
412    /// Executes [`munmap`](https://man7.org/linux/man-pages/man2/munmap.2.html) syscall akin to [`libc::munmap`].
413    fn munmap(
414        &mut self,
415        platform: &impl Platform,
416        addr: NonNull<c_void>,
417        length: c_size_t,
418    ) -> Result<()>;
419
420    /// Executes [`nanosleep`](https://man7.org/linux/man-pages/man2/nanosleep.2.html) syscall akin to [`libc::nanosleep`].
421    #[inline]
422    fn nanosleep(&mut self, req: &timespec, rem: Option<&mut timespec>) -> Result<()> {
423        self.execute(syscall::Nanosleep { req, rem })?
424    }
425
426    /// Executes [`open`](https://man7.org/linux/man-pages/man2/open.2.html) syscall akin to [`libc::open`].
427    ///
428    /// `pathname` argument must contain the trailing nul terminator byte.
429    fn open(&mut self, pathname: &[u8], flags: c_int, mode: Option<mode_t>) -> Result<c_int> {
430        self.execute(syscall::Open {
431            pathname,
432            flags,
433            mode,
434        })?
435    }
436
437    /// Executes [`poll`](https://man7.org/linux/man-pages/man2/poll.2.html) syscall akin to [`libc::poll`].
438    #[inline]
439    fn poll(&mut self, fds: &mut [pollfd], timeout: c_int) -> Result<c_int> {
440        self.execute(syscall::Poll { fds, timeout })?
441            .unwrap_or_else(|| self.attacked())
442    }
443
444    /// Executes [`read`](https://man7.org/linux/man-pages/man2/read.2.html) syscall akin to [`libc::read`].
445    #[inline]
446    fn read(&mut self, fd: c_int, buf: &mut [u8]) -> Result<c_size_t> {
447        self.execute(syscall::Read { fd, buf })?
448            .unwrap_or_else(|| self.attacked())
449    }
450
451    /// Executes [`readlink`](https://man7.org/linux/man-pages/man2/readlink.2.html) syscall akin to [`libc::readlink`].
452    ///
453    /// `pathname` argument must contain the trailing nul terminator byte.
454    #[inline]
455    fn readlink(&mut self, pathname: &[u8], buf: &mut [u8]) -> Result<c_size_t> {
456        self.execute(syscall::Readlink { pathname, buf })?
457            .unwrap_or_else(|| self.attacked())
458    }
459
460    /// Executes [`readv`](https://man7.org/linux/man-pages/man2/readv.2.html) syscall by mapping
461    /// it onto a single [`read`](https://man7.org/linux/man-pages/man2/read.2.html).
462    #[inline]
463    fn readv<T: ?Sized, U, V>(&mut self, fd: c_int, iovs: &mut T) -> Result<c_size_t>
464    where
465        for<'a> &'a T: IntoIterator<Item = &'a U>,
466        for<'a> &'a mut T: IntoIterator<Item = &'a mut V>,
467        U: AsRef<[u8]>,
468        V: AsMut<[u8]>,
469    {
470        self.execute(syscall::Readv { fd, iovs })?
471            .unwrap_or_else(|| self.attacked())
472    }
473
474    /// Executes [`recv`](https://man7.org/linux/man-pages/man2/recv.2.html) syscall akin to [`libc::recv`].
475    #[inline]
476    fn recv(&mut self, sockfd: c_int, buf: &mut [u8], flags: c_int) -> Result<c_size_t> {
477        self.execute(syscall::Recv { sockfd, buf, flags })?
478            .unwrap_or_else(|| self.attacked())
479    }
480
481    /// Executes [`recvfrom`](https://man7.org/linux/man-pages/man2/recvfrom.2.html) syscall akin to [`libc::recvfrom`].
482    #[inline]
483    fn recvfrom<'a>(
484        &mut self,
485        sockfd: c_int,
486        buf: &'a mut [u8],
487        flags: c_int,
488        src_addr: impl Into<SockaddrOutput<'a>>,
489    ) -> Result<c_size_t> {
490        self.execute(syscall::Recvfrom {
491            sockfd,
492            buf,
493            flags,
494            src_addr,
495        })?
496        .unwrap_or_else(|| self.attacked())
497    }
498
499    /// Executes [`rt_sigaction`](https://man7.org/linux/man-pages/man2/rt_sigaction.2.html).
500    #[inline]
501    fn rt_sigaction(
502        &mut self,
503        signum: c_int,
504        act: Option<&sigaction>,
505        oldact: Option<&mut Option<sigaction>>,
506        sigsetsize: c_size_t,
507    ) -> Result<()> {
508        if signum >= SIGRTMAX || sigsetsize != 8 {
509            return Err(EINVAL);
510        }
511        let tls = self.thread_local_storage();
512        if let Some(oldact) = oldact {
513            *oldact = tls.actions[signum as usize];
514        }
515        if let Some(act) = act {
516            tls.actions[signum as usize] = Some(*act);
517        }
518        Ok(())
519    }
520
521    /// Executes [`rt_sigprocmask`](https://man7.org/linux/man-pages/man2/rt_sigprocmask.2.html).
522    #[inline]
523    fn rt_sigprocmask(
524        &mut self,
525        how: c_int,
526        set: Option<&sigset_t>,
527        oldset: Option<&mut sigset_t>,
528        sigsetsize: c_size_t,
529    ) -> Result<()> {
530        self.execute(syscall::RtSigprocmask {
531            how,
532            set,
533            oldset,
534            sigsetsize,
535        })?
536    }
537
538    /// Executes [`send`](https://man7.org/linux/man-pages/man2/send.2.html) syscall akin to [`libc::send`].
539    #[inline]
540    fn send(&mut self, sockfd: c_int, buf: &[u8], flags: c_int) -> Result<c_size_t> {
541        self.execute(syscall::Send { sockfd, buf, flags })?
542            .unwrap_or_else(|| self.attacked())
543    }
544
545    /// Executes [`sendto`](https://man7.org/linux/man-pages/man2/sendto.2.html) syscall akin to [`libc::sendto`].
546    #[inline]
547    fn sendto<'a>(
548        &mut self,
549        sockfd: c_int,
550        buf: &'a [u8],
551        flags: c_int,
552        dest_addr: impl Into<SockaddrInput<'a>>,
553    ) -> Result<c_size_t> {
554        self.execute(syscall::Sendto {
555            sockfd,
556            buf,
557            flags,
558            dest_addr,
559        })?
560        .unwrap_or_else(|| self.attacked())
561    }
562
563    /// Executes [`setsockopt`](https://man7.org/linux/man-pages/man2/setsockopt.2.html) syscall akin to [`libc::setsockopt`].
564    #[inline]
565    fn setsockopt<'a>(
566        &mut self,
567        sockfd: c_int,
568        level: c_int,
569        optname: c_int,
570        optval: Option<impl Into<SockoptInput<'a>>>,
571    ) -> Result<c_int> {
572        self.execute(syscall::Setsockopt {
573            sockfd,
574            level,
575            optname,
576            optval,
577        })?
578    }
579
580    /// Executes [`set_tid_address`](https://man7.org/linux/man-pages/man2/set_tid_address.2.html).
581    #[inline]
582    fn set_tid_address(&mut self, tidptr: &mut c_int) -> Result<pid_t> {
583        self.execute(syscall::SetTidAddress { tidptr })
584    }
585
586    /// Executes [`sigaltstack`](https://man7.org/linux/man-pages/man2/sigaltstack.2.html) syscall akin to [`libc::sigaltstack`].
587    #[inline]
588    fn sigaltstack(&mut self, ss: Option<&stack_t>, old_ss: Option<&mut stack_t>) -> Result<()> {
589        self.execute(syscall::Sigaltstack { ss, old_ss })?
590    }
591
592    /// Executes [`socket`](https://man7.org/linux/man-pages/man2/socket.2.html) syscall akin to [`libc::socket`].
593    #[inline]
594    fn socket(&mut self, domain: c_int, typ: c_int, protocol: c_int) -> Result<c_int> {
595        self.execute(syscall::Socket {
596            domain,
597            typ,
598            protocol,
599        })?
600    }
601
602    /// Executes [`sync`](https://man7.org/linux/man-pages/man2/sync.2.html) syscall akin to [`libc::sync`].
603    #[inline]
604    fn sync(&mut self) -> Result<()> {
605        self.execute(syscall::Sync)?
606    }
607
608    /// Executes [`uname`](https://man7.org/linux/man-pages/man2/uname.2.html) syscall akin to [`libc::uname`].
609    #[inline]
610    fn uname(&mut self, buf: &mut utsname) -> Result<()> {
611        self.execute(syscall::Uname { buf })?
612    }
613
614    /// Executes [`write`](https://man7.org/linux/man-pages/man2/write.2.html) syscall akin to [`libc::write`].
615    #[inline]
616    fn write(&mut self, fd: c_int, buf: &[u8]) -> Result<c_size_t> {
617        self.execute(syscall::Write { fd, buf })?
618            .unwrap_or_else(|| self.attacked())
619    }
620
621    /// Executes [`writev`](https://man7.org/linux/man-pages/man2/writev.2.html) syscall by mapping
622    /// it onto a single [`write`](https://man7.org/linux/man-pages/man2/write.2.html).
623    #[inline]
624    fn writev<T: ?Sized, U>(&mut self, fd: c_int, iovs: &T) -> Result<c_size_t>
625    where
626        for<'a> &'a T: IntoIterator<Item = &'a U>,
627        U: AsRef<[u8]>,
628    {
629        self.execute(syscall::Writev { fd, iovs })?
630            .unwrap_or_else(|| self.attacked())
631    }
632
633    /// Executes a supported syscall expressed as an opaque 7-word array akin to [`libc::syscall`].
634    ///
635    /// # Safety
636    ///
637    /// This method is unsafe, because it allows execution of arbitrary syscalls on the host, which is
638    /// intrinsically unsafe.
639    ///
640    /// It can also produce multiple references to the same memory.
641    #[inline]
642    unsafe fn syscall(
643        &mut self,
644        platform: &impl Platform,
645        registers: [usize; 7],
646    ) -> Result<[usize; 2]> {
647        let [num, argv @ ..] = registers;
648        #[allow(non_upper_case_globals)]
649        match (num as _, argv) {
650            (SYS_accept, [sockfd, addr, addrlen, ..]) => {
651                let addr = if addr == 0 {
652                    None
653                } else {
654                    platform.validate_sockaddr_output(addr, addrlen).map(Some)?
655                };
656                self.accept(sockfd as _, addr).map(|ret| [ret as _, 0])
657            }
658            (SYS_accept4, [sockfd, addr, addrlen, flags, ..]) => {
659                let addr = if addr == 0 {
660                    None
661                } else {
662                    platform.validate_sockaddr_output(addr, addrlen).map(Some)?
663                };
664                self.accept4(sockfd as _, addr, flags as _)
665                    .map(|ret| [ret as _, 0])
666            }
667            (SYS_arch_prctl, [code, addr, ..]) => self
668                .arch_prctl(platform, code as _, addr as _)
669                .map(|_| [0, 0]),
670            (SYS_bind, [sockfd, addr, addrlen, ..]) => {
671                let addr = platform.validate_slice(addr, addrlen)?;
672                self.bind(sockfd as _, addr).map(|_| [0, 0])
673            }
674            (SYS_brk, [addr, ..]) => self
675                .brk(platform, NonNull::new(addr as _))
676                .map(|ret| [ret.as_ptr() as _, 0]),
677            (SYS_clock_getres, [clockid, res, ..]) => {
678                let res = if res == 0 {
679                    None
680                } else {
681                    platform.validate_mut(res).map(Some)?
682                };
683                self.clock_getres(clockid as _, res).map(|_| [0, 0])
684            }
685            (SYS_clock_gettime, [clockid, tp, ..]) => {
686                let tp = platform.validate_mut(tp)?;
687                self.clock_gettime(clockid as _, tp).map(|_| [0, 0])
688            }
689            (SYS_close, [fd, ..]) => self.close(fd as _).map(|_| [0, 0]),
690            (SYS_connect, [sockfd, addr, addrlen, ..]) => {
691                let addr = platform.validate_slice(addr, addrlen)?;
692                self.connect(sockfd as _, addr).map(|_| [0, 0])
693            }
694            (SYS_dup, [oldfd, ..]) => self.dup(oldfd as _).map(|_| [0, 0]),
695            (SYS_dup2, [oldfd, newfd, ..]) => self.dup2(oldfd as _, newfd as _).map(|_| [0, 0]),
696            (SYS_dup3, [oldfd, newfd, flags, ..]) => self
697                .dup3(oldfd as _, newfd as _, flags as _)
698                .map(|_| [0, 0]),
699            (SYS_epoll_create1, [flags, ..]) => {
700                self.epoll_create1(flags as _).map(|ret| [ret as _, 0])
701            }
702            (SYS_epoll_ctl, [epfd, op, fd, event, ..]) => {
703                let event = platform.validate(event)?;
704                self.epoll_ctl(epfd as _, op as _, fd as _, event)
705                    .map(|_| [0, 0])
706            }
707            (SYS_epoll_pwait, [epfd, events, maxevents, timeout, sigmask, ..]) => {
708                let events = platform.validate_slice_mut(events, maxevents)?;
709                if sigmask == 0 {
710                    self.epoll_wait(epfd as _, events, timeout as _)
711                } else {
712                    let sigmask = platform.validate(sigmask)?;
713                    self.epoll_pwait(epfd as _, events, timeout as _, sigmask)
714                }
715                .map(|ret| [ret as _, 0])
716            }
717            (SYS_epoll_wait, [epfd, events, maxevents, timeout, ..]) => {
718                let events = platform.validate_slice_mut(events, maxevents)?;
719                self.epoll_wait(epfd as _, events, timeout as _)
720                    .map(|ret| [ret as _, 0])
721            }
722            (SYS_eventfd2, [initval, flags, ..]) => self
723                .eventfd2(initval as _, flags as _)
724                .map(|ret| [ret as _, 0]),
725            (SYS_exit, [status, ..]) => self.exit(status as _).map(|_| self.attacked()),
726            (SYS_exit_group, [status, ..]) => self.exit_group(status as _).map(|_| self.attacked()),
727            (SYS_fcntl, [fd, cmd, arg, ..]) => self
728                .fcntl(fd as _, cmd as _, arg as _)
729                .map(|ret| [ret as _, 0]),
730            (SYS_fstat, [fd, statbuf, ..]) => {
731                let statbuf = platform.validate_mut(statbuf)?;
732                self.fstat(fd as _, statbuf).map(|_| [0, 0])
733            }
734            (SYS_getegid, ..) => self.getegid().map(|ret| [ret as _, 0]),
735            (SYS_geteuid, ..) => self.geteuid().map(|ret| [ret as _, 0]),
736            (SYS_getgid, ..) => self.getgid().map(|ret| [ret as _, 0]),
737            (SYS_getpid, ..) => self.getpid().map(|ret| [ret as _, 0]),
738            (SYS_getrandom, [buf, buflen, flags, ..]) => {
739                let buf = platform.validate_slice_mut(buf, buflen)?;
740                self.getrandom(buf, flags as _).map(|ret| [ret as _, 0])
741            }
742            (SYS_getsockname, [sockfd, addr, addrlen, ..]) => {
743                let addr = platform.validate_sockaddr_output(addr, addrlen)?;
744                self.getsockname(sockfd as _, addr).map(|_| [0, 0])
745            }
746            (SYS_getuid, ..) => self.getuid().map(|ret| [ret as _, 0]),
747            (SYS_ioctl, [fd, request, argp, ..]) => {
748                let argp = if argp == 0 {
749                    None
750                } else {
751                    match request as _ {
752                        FIONBIO | FIONREAD => platform.validate_mut::<c_int>(argp).map(|argp| {
753                            Some(slice::from_raw_parts_mut(
754                                argp as *mut _ as _,
755                                size_of::<c_int>(),
756                            ))
757                        })?,
758                        _ => return Err(ENOTSUP),
759                    }
760                };
761                self.ioctl(fd as _, request as _, argp)
762                    .map(|ret| [ret as _, 0])
763            }
764            (SYS_listen, [sockfd, backlog, ..]) => {
765                self.listen(sockfd as _, backlog as _).map(|_| [0, 0])
766            }
767            (SYS_madvise, [addr, length, advice, ..]) => {
768                let addr = NonNull::new(addr as _).ok_or(EFAULT)?;
769                self.madvise(platform, addr, length, advice as _)
770                    .map(|_| [0, 0])
771            }
772            (SYS_mmap, [addr, length, prot, flags, fd, offset, ..]) => self
773                .mmap(
774                    platform,
775                    NonNull::new(addr as _),
776                    length,
777                    prot as _,
778                    flags as _,
779                    fd as _,
780                    offset as _,
781                )
782                .map(|ret| [ret.as_ptr() as _, 0]),
783            (SYS_mprotect, [addr, len, prot, ..]) => {
784                let addr = NonNull::new(addr as _).ok_or(EFAULT)?;
785                self.mprotect(platform, addr, len, prot as _)
786                    .map(|_| [0, 0])
787            }
788            (SYS_mremap, [old_address, old_size, new_size, flags, new_address, ..]) => {
789                let old_address = NonNull::new(old_address as _).ok_or(EFAULT)?;
790                let flags = match (flags as _, new_address) {
791                    (0, 0) => None,
792                    (MREMAP_MAYMOVE, 0) => Some(Default::default()),
793                    (flags, 0) if flags == MREMAP_MAYMOVE | MREMAP_DONTUNMAP => Some(MremapFlags {
794                        DONTUNMAP: true,
795                        ..Default::default()
796                    }),
797                    (flags, 0) if flags & MREMAP_FIXED != 0 => return Err(EINVAL),
798                    (flags, new_address) if flags == MREMAP_MAYMOVE | MREMAP_FIXED => {
799                        Some(MremapFlags {
800                            FIXED: Some(NonNull::new(new_address as _).unwrap()),
801                            ..Default::default()
802                        })
803                    }
804                    (flags, new_address)
805                        if flags == MREMAP_MAYMOVE | MREMAP_FIXED | MREMAP_DONTUNMAP =>
806                    {
807                        Some(MremapFlags {
808                            DONTUNMAP: true,
809                            FIXED: Some(NonNull::new(new_address as _).unwrap()),
810                        })
811                    }
812                    _ => return Err(EINVAL),
813                };
814                self.mremap(platform, old_address, old_size, new_size, flags)
815                    .map(|ret| [ret.as_ptr() as _, 0])
816            }
817            (SYS_munmap, [addr, length, ..]) => {
818                let addr = NonNull::new(addr as _).ok_or(EFAULT)?;
819                self.munmap(platform, addr, length).map(|_| [0, 0])
820            }
821            (SYS_nanosleep, [req, rem, ..]) => {
822                let req = platform.validate(req)?;
823                let rem = if rem == 0 {
824                    None
825                } else {
826                    platform.validate_mut(rem).map(Some)?
827                };
828                self.nanosleep(req, rem).map(|_| [0, 0])
829            }
830            (SYS_open, [pathname, flags, mode, ..]) => {
831                let pathname = platform.validate_str(pathname)?;
832                let mode = if mode == 0 { None } else { Some(mode as _) };
833                self.open(pathname, flags as _, mode)
834                    .map(|ret| [ret as _, 0])
835            }
836            (SYS_poll, [fds, nfds, timeout, ..]) => {
837                let fds = platform.validate_slice_mut(fds, nfds)?;
838                self.poll(fds, timeout as _).map(|ret| [ret as _, 0])
839            }
840            (SYS_read, [fd, buf, count, ..]) => {
841                let buf = platform.validate_slice_mut(buf, count)?;
842                self.read(fd as _, buf).map(|ret| [ret, 0])
843            }
844            (SYS_readlink, [pathname, buf, bufsiz, ..]) => {
845                let pathname = platform.validate_str(pathname)?;
846                let buf = platform.validate_slice_mut(buf, bufsiz)?;
847                self.readlink(pathname, buf).map(|ret| [ret, 0])
848            }
849            (SYS_readv, [fd, iov, iovcnt, ..]) => {
850                let iovs = platform.validate_iovec_slice_mut(iov, iovcnt)?;
851                self.readv(fd as _, iovs).map(|ret| [ret, 0])
852            }
853            (SYS_recvfrom, [sockfd, buf, len, flags, src_addr, addrlen, ..]) => {
854                let buf = platform.validate_slice_mut(buf, len)?;
855                if src_addr == 0 {
856                    self.recv(sockfd as _, buf, flags as _)
857                } else {
858                    let src_addr = platform.validate_sockaddr_output(src_addr, addrlen)?;
859                    self.recvfrom(sockfd as _, buf, flags as _, src_addr)
860                }
861                .map(|ret| [ret, 0])
862            }
863            (SYS_rt_sigaction, [signum, act, oldact, sigsetsize, ..]) => {
864                let act = if act == 0 {
865                    None
866                } else {
867                    platform.validate(act).map(Some)?
868                };
869                if oldact == 0 {
870                    self.rt_sigaction(signum as _, act, None, sigsetsize as _)?
871                } else {
872                    let sys_oldact = platform.validate_mut(oldact)?;
873                    let mut oldact = None;
874                    self.rt_sigaction(signum as _, act, Some(&mut oldact), sigsetsize as _)?;
875                    if let Some(oldact) = oldact {
876                        *sys_oldact = oldact;
877                    }
878                }
879                Ok([0, 0])
880            }
881            (SYS_rt_sigprocmask, [how, set, oldset, sigsetsize, ..]) => {
882                let set = if set == 0 {
883                    None
884                } else {
885                    platform.validate(set).map(Some)?
886                };
887                let oldset = if oldset == 0 {
888                    None
889                } else {
890                    platform.validate_mut(oldset).map(Some)?
891                };
892                self.rt_sigprocmask(how as _, set, oldset, sigsetsize as _)
893                    .map(|_| [0, 0])
894            }
895            (SYS_sendto, [sockfd, buf, len, flags, dest_addr, addrlen]) => {
896                let buf = platform.validate_slice(buf, len)?;
897                if dest_addr == 0 {
898                    self.send(sockfd as _, buf, flags as _)
899                } else {
900                    let dest_addr = platform.validate_slice(dest_addr, addrlen)?;
901                    self.sendto(sockfd as _, buf, flags as _, dest_addr)
902                }
903                .map(|ret| [ret, 0])
904            }
905            (SYS_setsockopt, [sockfd, level, optname, optval, optlen, ..]) => {
906                let optval = if optval == 0 {
907                    None
908                } else {
909                    platform.validate_slice::<u8>(optval, optlen).map(Some)?
910                };
911                self.setsockopt(sockfd as _, level as _, optname as _, optval)
912                    .map(|ret| [ret as _, 0])
913            }
914            (SYS_set_tid_address, [tidptr, ..]) => {
915                let tidptr = platform.validate_mut(tidptr)?;
916                self.set_tid_address(tidptr).map(|ret| [ret as _, 0])
917            }
918            (SYS_sigaltstack, [ss, old_ss, ..]) => {
919                let ss = if ss == 0 {
920                    None
921                } else {
922                    platform.validate(ss).map(Some)?
923                };
924                let old_ss = if old_ss == 0 {
925                    None
926                } else {
927                    platform.validate_mut(old_ss).map(Some)?
928                };
929                self.sigaltstack(ss, old_ss).map(|_| [0, 0])
930            }
931            (SYS_socket, [domain, typ, protocol, ..]) => self
932                .socket(domain as _, typ as _, protocol as _)
933                .map(|ret| [ret as _, 0]),
934            (SYS_sync, ..) => self.sync().map(|_| [0, 0]),
935            (SYS_uname, [buf, ..]) => {
936                let buf = platform.validate_mut(buf)?;
937                self.uname(buf).map(|_| [0, 0])
938            }
939            (SYS_write, [fd, buf, count, ..]) => {
940                let buf = platform.validate_slice(buf, count)?;
941                self.write(fd as _, buf).map(|ret| [ret, 0])
942            }
943            (SYS_writev, [fd, iov, iovcnt, ..]) => {
944                let iovs = platform.validate_iovec_slice(iov, iovcnt)?;
945                self.writev(fd as _, iovs).map(|ret| [ret, 0])
946            }
947            _ => Err(ENOSYS),
948        }
949    }
950
951    // GDB calls, sorted alphabetically.
952
953    #[cfg_attr(feature = "doc", doc = "Executes [gdbstub::conn::Connection::flush]")]
954    #[inline]
955    fn gdb_flush(&mut self) -> Result<()> {
956        self.execute(gdbcall::Flush)?
957    }
958
959    #[cfg_attr(
960        feature = "doc",
961        doc = "Executes [gdbstub::conn::Connection::on_session_start]"
962    )]
963    #[inline]
964    fn gdb_on_session_start(&mut self) -> Result<()> {
965        self.execute(gdbcall::OnSessionStart)?
966    }
967
968    #[cfg_attr(feature = "doc", doc = "Executes [gdbstub::conn::ConnectionExt::peek]")]
969    #[inline]
970    fn gdb_peek(&mut self) -> Result<Option<u8>> {
971        self.execute(gdbcall::Peek)?
972    }
973
974    #[cfg_attr(feature = "doc", doc = "Executes [gdbstub::conn::ConnectionExt::read]")]
975    #[inline]
976    fn gdb_read(&mut self) -> Result<u8> {
977        self.execute(gdbcall::Read)?
978    }
979
980    #[cfg_attr(feature = "doc", doc = "Executes [gdbstub::conn::Connection::write]")]
981    #[inline]
982    fn gdb_write(&mut self, byte: u8) -> Result<()> {
983        self.execute(gdbcall::Write { byte })?
984    }
985
986    #[cfg_attr(
987        feature = "doc",
988        doc = "Executes [gdbstub::conn::Connection::write_all] and returns the amount of bytes written"
989    )]
990    #[inline]
991    fn gdb_write_all(&mut self, buf: &[u8]) -> Result<usize> {
992        self.execute(gdbcall::WriteAll { buf })?
993            .unwrap_or_else(|| self.attacked())
994    }
995
996    // Enarx calls, sorted alphabetically.
997
998    /// Request an additional memory region and return the virtual address of allocated region.
999    ///
1000    /// # Arguments
1001    ///
1002    /// - `size_exponent`: Page size expressed as an exponent of 2
1003    /// - `pages`: Number of pages to allocate
1004    /// - `addr`: Guest physical address where the memory should be allocated
1005    #[inline]
1006    fn balloon_memory(
1007        &mut self,
1008        size_exponent: usize,
1009        pages: usize,
1010        addr: *mut c_void,
1011    ) -> Result<usize> {
1012        self.execute(enarxcall::BalloonMemory {
1013            size_exponent,
1014            pages,
1015            addr,
1016        })?
1017    }
1018
1019    /// Execute `cpuid` instruction storing the result in `result`.
1020    #[inline]
1021    fn cpuid(&mut self, leaf: u32, sub_leaf: u32, result: &mut CpuidResult) -> Result<()> {
1022        self.execute(enarxcall::Cpuid {
1023            leaf,
1024            sub_leaf,
1025            result,
1026        })?
1027    }
1028
1029    /// Requests SGX quote from the host given a report and returns the length of the quote on success.
1030    #[inline]
1031    fn get_sgx_quote(&mut self, report: &sgx::Report, quote: &mut [u8]) -> Result<usize> {
1032        self.execute(enarxcall::GetSgxQuote { report, quote })?
1033            .unwrap_or_else(|| self.attacked())
1034    }
1035
1036    /// Requests the SGX quote size from the host.
1037    #[inline]
1038    fn get_sgx_quote_size(&mut self) -> Result<usize> {
1039        self.execute(enarxcall::GetSgxQuoteSize)?
1040    }
1041
1042    /// Requests [SGX `TargetInfo`](sgx::TargetInfo) from the host.
1043    #[inline]
1044    fn get_sgx_target_info(&mut self, info: &mut sgx::TargetInfo) -> Result<()> {
1045        self.execute(enarxcall::GetSgxTargetInfo { info })?
1046    }
1047
1048    /// Requests SNP VCEK from the host.
1049    #[inline]
1050    fn get_snp_vcek(&mut self, vcek: &mut [u8]) -> Result<usize> {
1051        self.execute(enarxcall::GetSnpVcek { vcek })?
1052            .unwrap_or_else(|| self.attacked())
1053    }
1054
1055    /// Gets number of memory slots available for ballooning from the host.
1056    ///
1057    /// KVM only has a limited number of memory ballooning slots, which varies by technology and kernel version.
1058    /// Knowing this number helps the shim allocator to decide how much memory to allocate for each slot.
1059    #[inline]
1060    fn mem_info(&mut self) -> Result<usize> {
1061        self.execute(enarxcall::MemInfo)?
1062    }
1063
1064    /// Notify the host about `mmmap()`.
1065    #[inline]
1066    fn mmap_host(&mut self, addr: NonNull<c_void>, length: usize, prot: c_int) -> Result<()> {
1067        self.execute(enarxcall::MmapHost { addr, length, prot })?
1068    }
1069
1070    /// Notify the host about `mprotect()`.
1071    #[inline]
1072    fn mprotect_host(&mut self, addr: NonNull<c_void>, length: usize, prot: c_int) -> Result<()> {
1073        self.execute(enarxcall::MprotectHost { addr, length, prot })?
1074    }
1075
1076    /// Notify the host about `munmap()`.
1077    #[inline]
1078    fn munmap_host(&mut self, addr: NonNull<c_void>, length: usize) -> Result<()> {
1079        self.execute(enarxcall::MunmapHost { addr, length })?
1080    }
1081
1082    /// Within an address range inside the enclave, ask host to set page type to
1083    /// 'trimmed'. Address and length must be page-aligned. Shim must validate
1084    /// and acknowledge the changes with ENCLU[EACCEPT], in order for them to
1085    /// take effect.
1086    #[inline]
1087    fn trim_sgx_pages(&mut self, addr: NonNull<c_void>, length: usize) -> Result<()> {
1088        self.execute(enarxcall::TrimSgxPages { addr, length })?
1089    }
1090}