diff --git a/crates/molotov-core/src/lib.rs b/crates/molotov-core/src/lib.rs index 85c0939..4e6eb81 100644 --- a/crates/molotov-core/src/lib.rs +++ b/crates/molotov-core/src/lib.rs @@ -1,3 +1,4 @@ // SPDX-License-Identifier: GPL-3.0-or-later pub mod elf; +pub mod mmap; pub mod symbols; diff --git a/crates/molotov-core/src/mmap.rs b/crates/molotov-core/src/mmap.rs new file mode 100644 index 0000000..552c8df --- /dev/null +++ b/crates/molotov-core/src/mmap.rs @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +use std::ptr; + +pub const PAGE_SIZE: usize = 4096; + +pub struct MappedImage { + base: *mut u8, + size: usize, +} + +impl MappedImage { + pub const fn page_align_down(addr: usize) -> usize { + addr & !(PAGE_SIZE - 1) + } + + pub const fn page_align_up(addr: usize) -> usize { + (addr + PAGE_SIZE - 1) & !(PAGE_SIZE - 1) + } + + pub fn allocate_anonymous(size: usize) -> Result { + let aligned_size = Self::page_align_up(size); + let ptr = unsafe { + libc::mmap( + ptr::null_mut(), + aligned_size, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_PRIVATE | libc::MAP_ANONYMOUS, + -1, + 0, + ) + }; + + if ptr == libc::MAP_FAILED { + Err("mmap failed to allocate anonymous memory".to_string()) + } else { + Ok(Self { + base: ptr as *mut u8, + size: aligned_size, + }) + } + } + + pub fn base_addr(&self) -> *mut u8 { + self.base + } + + pub fn size(&self) -> usize { + self.size + } + + pub fn protect(&self, offset: usize, len: usize, prot: i32) -> Result<(), String> { + let page_start = Self::page_align_down(offset); + let page_end = Self::page_align_up(offset + len); + let aligned_len = page_end - page_start; + + let ret = unsafe { + libc::mprotect( + self.base.add(page_start) as *mut libc::c_void, + aligned_len, + prot, + ) + }; + + if ret == 0 { + Ok(()) + } else { + Err(format!("mprotect failed with errno {}", std::io::Error::last_os_error())) + } + } +} + +impl Drop for MappedImage { + fn drop(&mut self) { + if !self.base.is_null() { + unsafe { + libc::munmap(self.base as *mut libc::c_void, self.size); + } + } + } +} + +unsafe impl Send for MappedImage {} +unsafe impl Sync for MappedImage {} diff --git a/crates/molotov-core/tests/mmap_test.rs b/crates/molotov-core/tests/mmap_test.rs new file mode 100644 index 0000000..dad8551 --- /dev/null +++ b/crates/molotov-core/tests/mmap_test.rs @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +use molotov_core::mmap::MappedImage; + +#[test] +fn test_page_alignment_helper() { + assert_eq!(MappedImage::page_align_down(4096), 4096); + assert_eq!(MappedImage::page_align_down(4097), 4096); + assert_eq!(MappedImage::page_align_up(4095), 4096); + assert_eq!(MappedImage::page_align_up(4096), 4096); + assert_eq!(MappedImage::page_align_up(4097), 8192); +} + +#[test] +fn test_mmap_reservation_and_drop() { + let mapping = MappedImage::allocate_anonymous(65536).expect("Should mmap virtual address space"); + assert!(!mapping.base_addr().is_null()); + assert_eq!(mapping.size(), 65536); + // Dropping mapping unmaps memory automatically via RAII +}