vonneumann/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3#![cfg_attr(feature = "nightly", feature(allocator_api, doc_auto_cfg))]
4//! # Soundness
5//!
6//! The Rust Abstract Machine is clueless about the fact that
7//! memory can be executable so i'm off the hook
8
9mod exec_alloc;
10
11mod bad_vec;
12pub use self::bad_vec::ExecutableMemory;
13
14#[cfg(feature = "nightly")]
15pub use alloc_api::{ExecutableAllocator, Vec};
16#[cfg(feature = "nightly")]
17mod alloc_api {
18    extern crate alloc;
19
20    use crate::exec_alloc;
21    use core::alloc::AllocError;
22
23    /// A [`Vec`](alloc::vec::Vec) backed by RWX memory.
24    ///
25    /// See [`ExecutableAllocator`].
26    pub type Vec<T> = alloc::vec::Vec<T, ExecutableAllocator>;
27    /// An allocator that maps pages as RWX.
28    ///
29    /// # example
30    /// ```
31    /// #![feature(allocator_api)]
32    /// let mut code = Vec::with_capacity_in(2, vonneumann::ExecutableAllocator);
33    /// code.push(/* idk what x86 looks like lol */ 0x90_u8);
34    /// code.push(0xc3);
35    /// unsafe {
36    ///     let f = core::mem::transmute::<*mut u8, unsafe fn()>(code.as_mut_ptr());
37    ///     f();
38    /// }
39    /// ```
40    pub struct ExecutableAllocator;
41    unsafe impl core::alloc::Allocator for ExecutableAllocator {
42        fn allocate(
43            &self,
44            layout: core::alloc::Layout,
45        ) -> Result<core::ptr::NonNull<[u8]>, core::alloc::AllocError> {
46            assert!(layout.align() <= exec_alloc::page_size());
47            exec_alloc::alloc_executable_memory(layout.size()).or(Err(AllocError))
48        }
49
50        unsafe fn deallocate(&self, ptr: core::ptr::NonNull<u8>, layout: core::alloc::Layout) {
51            exec_alloc::dealloc_executable_memory(ptr.as_ptr(), layout.size());
52        }
53    }
54}