sallyport 0.6.3

API for the Enarx hypervisor-microkernel boundary
Documentation
// SPDX-License-Identifier: Apache-2.0

use super::syscall::types::SockaddrOutput;
use crate::libc::{iovec, EINVAL};

use core::ffi::c_int;
use core::slice;

/// Platform-specific functionality.
pub trait Platform {
    /// Validates that the memory pointed to by `ptr` of the type `T` is:
    /// * in valid address space and writable for the lifetime of `self`.
    /// * "dereferenceable" in the sense defined in [the ptr module documentation].
    /// * ptr is non-null and aligned
    /// * not borrowed already
    /// and registers the memory as borrowed mutably.
    ///
    /// Returns a mutable borrow if valid, otherwise [`EINVAL`](libc::EINVAL).
    ///
    /// [the ptr module documentation]: core::ptr#safety
    fn validate_mut<T>(&self, ptr: usize) -> Result<&mut T, c_int>;

    /// Validates that the memory pointed to by `ptr` of the type `T` is:
    /// * in valid address space and readable for the lifetime of `self`.
    /// * "dereferenceable" in the sense defined in [the ptr module documentation].
    /// * ptr is non-null and aligned
    /// * not borrowed already
    /// and registers the memory as borrowed.
    ///
    /// Returns an immutable borrow if valid, otherwise [`EINVAL`](libc::EINVAL).
    ///
    /// [the ptr module documentation]: core::ptr#safety
    fn validate<T>(&self, ptr: usize) -> Result<&T, c_int>;

    /// Validates that a region for `count` elements of type `T` is:
    /// * in valid address space and writable for the lifetime of `self`.
    /// * "dereferenceable" in the sense defined in [the ptr module documentation].
    /// * ptr is non-null and aligned
    /// * not borrowed already
    /// and registers the memory as borrowed mutably.
    ///
    /// Returns a mutable borrow if valid, otherwise [`EINVAL`](libc::EINVAL).
    ///
    /// [the ptr module documentation]: core::ptr#safety
    fn validate_slice_mut<T: Sized>(&self, ptr: usize, count: usize) -> Result<&mut [T], c_int>;

    /// Validates that a region of memory is valid for read-only access for `count` elements of type `T`.
    /// * in valid address space and writable for the lifetime of `self`.
    /// * "dereferenceable" in the sense defined in [the ptr module documentation].
    /// * ptr is non-null and aligned
    /// * not borrowed already
    /// and registers the memory as borrowed.
    ///
    /// Returns an immutable borrow if valid, otherwise [`EINVAL`](libc::EINVAL).
    ///
    /// [the ptr module documentation]: core::ptr#safety
    fn validate_slice<T: Sized>(&self, ptr: usize, count: usize) -> Result<&[T], c_int>;

    /// Validates that pointer `iov` points to represents a slice of `iovcnt` pointers to [`libc::iovec`] structures
    /// valid for read-write access.
    ///
    /// Also checks, that memory is:
    /// * in valid address space and writable for the lifetime of `self`.
    /// * "dereferenceable" in the sense defined in [the ptr module documentation].
    /// * not borrowed already
    /// * and pointers are non-null and aligned
    /// and registers the memory as borrowed mutably.
    ///
    /// Returns a mutable borrow of the [`libc::iovec`] structs as a 2-dimensional slice
    /// of mutable byte buffer borrows if valid, otherwise [`EINVAL`](libc::EINVAL).
    #[inline]
    fn validate_iovec_slice_mut(
        &self,
        iov: usize,
        iovcnt: usize,
    ) -> Result<&mut [&mut [u8]], c_int> {
        let iovec_slice = self.validate_slice::<iovec>(iov, iovcnt)?;
        for iovec in iovec_slice {
            self.validate_slice_mut::<u8>(iovec.iov_base as _, iovec.iov_len)?;
        }

        // Safety: checked all slices before
        Ok(unsafe { slice::from_raw_parts_mut(iov as _, iovcnt) })
    }

    /// Validates that pointer `iov` points to represents a slice of `iovcnt` pointers to [`libc::iovec`] structures
    /// valid for read-only access.
    ///
    /// Also checks, that the memory is:
    /// * in valid address space and readable for the lifetime of `self`.
    /// * "dereferenceable" in the sense defined in [the ptr module documentation].
    /// * not borrowed already
    /// * and pointers are non-null and aligned
    /// and registers the memory as borrowed.
    ///
    /// Returns an immutable borrow of the [`libc::iovec`] structs as a 2-dimensional slice
    /// of immutable byte buffer borrows if valid, otherwise [`EINVAL`](libc::EINVAL).
    #[inline]
    fn validate_iovec_slice(&self, iov: usize, iovcnt: usize) -> Result<&[&[u8]], c_int> {
        let iovec_slice = self.validate_slice::<iovec>(iov, iovcnt)?;
        for iovec in iovec_slice {
            self.validate_slice::<u8>(iovec.iov_base as _, iovec.iov_len)?;
        }

        // Safety: checked all slices before
        Ok(unsafe { slice::from_raw_parts(iov as _, iovcnt) })
    }

    /// Validates that a region of memory represents a C string and is valid for read-only access.
    ///
    /// Also checks, that the memory is:
    /// * in valid address space and readable for the lifetime of `self`.
    /// * "dereferenceable" in the sense defined in [the ptr module documentation].
    /// * ptr is non-null and aligned
    /// * not borrowed already
    /// and registers the memory as borrowed.
    ///
    /// Returns an immutable borrow of bytes of the string with the nul terminator byte if valid,
    /// otherwise [`EINVAL`](libc::EINVAL).
    #[inline]
    fn validate_str(&self, ptr: usize) -> Result<&[u8], c_int> {
        let mut p = ptr;

        loop {
            let byte = self.validate::<u8>(p)?;
            p += 1;
            if *byte == 0 {
                break;
            }
        }

        let len = p.checked_sub(ptr).ok_or(EINVAL)?;

        // Safety: checked all bytes before
        Ok(unsafe { slice::from_raw_parts(ptr as *const u8, len) })
    }

    /// Validates that pointer `addrlen` points to `socklen_t` and `addr` points to
    /// a byte array of size `*addrlen` and is valid for read-write access.
    ///
    /// Also checks that the memory is:
    /// * in valid address space and writable for the lifetime of `self`.
    /// * "dereferenceable" in the sense defined in [the ptr module documentation].
    /// * not borrowed already
    /// * and pointers are non-null and aligned
    /// and registers the memory as borrowed.
    ///
    /// Returns a `SockaddrOutput`, otherwise [`EINVAL`](libc::EINVAL).
    #[inline]
    fn validate_sockaddr_output(
        &self,
        addr: usize,
        addrlen: usize,
    ) -> Result<SockaddrOutput, c_int> {
        let addrlen = self.validate_mut(addrlen)?;
        let addr = self.validate_slice_mut(addr, *addrlen as _)?;
        Ok(SockaddrOutput::new(addr, addrlen))
    }
}