From 1adf6f15e438cd9bca10c8353003392a994cd039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Thu, 1 Dec 2022 20:57:19 +0100 Subject: [PATCH] Moves memory_management into its own file. --- src/jit.rs | 154 +----------------------------------- src/lib.rs | 2 + src/memory_management.rs | 164 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 151 deletions(-) create mode 100644 src/memory_management.rs diff --git a/src/jit.rs b/src/jit.rs index e49379c2..b560128c 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -10,21 +10,6 @@ // the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -#[cfg(not(target_os = "windows"))] -extern crate libc; -#[cfg(not(target_os = "windows"))] -use libc::c_void; - -#[cfg(target_os = "windows")] -use winapi::{ - ctypes::c_void, - shared::minwindef, - um::errhandlingapi::GetLastError, - um::memoryapi::{VirtualAlloc, VirtualFree, VirtualProtect}, - um::sysinfoapi::{GetSystemInfo, SYSTEM_INFO}, - um::winnt, -}; - use rand::{rngs::SmallRng, Rng, SeedableRng}; use std::{fmt::Debug, marker::PhantomData, mem, ptr}; @@ -32,6 +17,9 @@ use crate::{ ebpf::{self, FIRST_SCRATCH_REG, FRAME_PTR_REG, INSN_SIZE, SCRATCH_REGS, STACK_PTR_REG}, elf::Executable, error::EbpfError, + memory_management::{ + allocate_pages, free_pages, get_system_page_size, protect_pages, round_to_page_size, + }, memory_region::{AccessType, MemoryMapping}, vm::{Config, ContextObject, ProgramResult, RuntimeEnvironment, SyscallFunction}, x86::*, @@ -52,142 +40,6 @@ pub struct JitProgram { _marker: PhantomData, } -#[cfg(not(target_os = "windows"))] -macro_rules! libc_error_guard { - (succeeded?, mmap, $addr:expr, $($arg:expr),*) => {{ - *$addr = libc::mmap(*$addr, $($arg),*); - *$addr != libc::MAP_FAILED - }}; - (succeeded?, $function:ident, $($arg:expr),*) => { - libc::$function($($arg),*) == 0 - }; - ($function:ident, $($arg:expr),* $(,)?) => {{ - const RETRY_COUNT: usize = 3; - for i in 0..RETRY_COUNT { - if libc_error_guard!(succeeded?, $function, $($arg),*) { - break; - } else if i + 1 == RETRY_COUNT { - let args = vec![$(format!("{:?}", $arg)),*]; - #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))] - let errno = *libc::__error(); - #[cfg(any(target_os = "android", target_os = "netbsd", target_os = "openbsd"))] - let errno = *libc::__errno(); - #[cfg(target_os = "linux")] - let errno = *libc::__errno_location(); - return Err(EbpfError::LibcInvocationFailed(stringify!($function), args, errno)); - } - } - }}; -} - -#[cfg(target_os = "windows")] -macro_rules! winapi_error_guard { - (succeeded?, VirtualAlloc, $addr:expr, $($arg:expr),*) => {{ - *$addr = VirtualAlloc(*$addr, $($arg),*); - !(*$addr).is_null() - }}; - (succeeded?, $function:ident, $($arg:expr),*) => { - $function($($arg),*) != 0 - }; - ($function:ident, $($arg:expr),* $(,)?) => {{ - if !winapi_error_guard!(succeeded?, $function, $($arg),*) { - let args = vec![$(format!("{:?}", $arg)),*]; - let errno = GetLastError(); - return Err(EbpfError::WinapiInvocationFailed(stringify!($function), args, errno)); - } - }}; -} - -pub fn get_system_page_size() -> usize { - #[cfg(not(target_os = "windows"))] - unsafe { - libc::sysconf(libc::_SC_PAGESIZE) as usize - } - #[cfg(target_os = "windows")] - unsafe { - let mut system_info: SYSTEM_INFO = mem::zeroed(); - GetSystemInfo(&mut system_info); - system_info.dwPageSize as usize - } -} - -pub fn round_to_page_size(value: usize, page_size: usize) -> usize { - (value + page_size - 1) / page_size * page_size -} - -pub unsafe fn allocate_pages(size_in_bytes: usize) -> Result<*mut u8, EbpfError> { - let mut raw: *mut c_void = std::ptr::null_mut(); - #[cfg(not(target_os = "windows"))] - libc_error_guard!( - mmap, - &mut raw, - size_in_bytes, - libc::PROT_READ | libc::PROT_WRITE, - libc::MAP_ANONYMOUS | libc::MAP_PRIVATE, - 0, - 0, - ); - #[cfg(target_os = "windows")] - winapi_error_guard!( - VirtualAlloc, - &mut raw, - size_in_bytes, - winnt::MEM_RESERVE | winnt::MEM_COMMIT, - winnt::PAGE_READWRITE, - ); - Ok(raw as *mut u8) -} - -pub unsafe fn free_pages(raw: *mut u8, size_in_bytes: usize) -> Result<(), EbpfError> { - #[cfg(not(target_os = "windows"))] - libc_error_guard!(munmap, raw as *mut _, size_in_bytes); - #[cfg(target_os = "windows")] - winapi_error_guard!( - VirtualFree, - raw as *mut _, - size_in_bytes, - winnt::MEM_RELEASE, // winnt::MEM_DECOMMIT - ); - Ok(()) -} - -pub unsafe fn protect_pages( - raw: *mut u8, - size_in_bytes: usize, - executable_flag: bool, -) -> Result<(), EbpfError> { - #[cfg(not(target_os = "windows"))] - { - libc_error_guard!( - mprotect, - raw as *mut _, - size_in_bytes, - if executable_flag { - libc::PROT_EXEC | libc::PROT_READ - } else { - libc::PROT_READ - }, - ); - } - #[cfg(target_os = "windows")] - { - let mut old: minwindef::DWORD = 0; - let ptr_old: *mut minwindef::DWORD = &mut old; - winapi_error_guard!( - VirtualProtect, - raw as *mut _, - size_in_bytes, - if executable_flag { - winnt::PAGE_EXECUTE_READ - } else { - winnt::PAGE_READONLY - }, - ptr_old, - ); - } - Ok(()) -} - impl JitProgram { fn new(pc: usize, code_size: usize) -> Result { let page_size = get_system_page_size(); diff --git a/src/lib.rs b/src/lib.rs index b52caa14..bd1b3069 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,8 @@ pub mod insn_builder; pub mod interpreter; #[cfg(all(feature = "jit", not(target_os = "windows"), target_arch = "x86_64"))] mod jit; +#[cfg(feature = "jit")] +mod memory_management; pub mod memory_region; pub mod static_analysis; pub mod syscalls; diff --git a/src/memory_management.rs b/src/memory_management.rs new file mode 100644 index 00000000..20b5261a --- /dev/null +++ b/src/memory_management.rs @@ -0,0 +1,164 @@ +// Copyright 2022 Solana Maintainers +// +// Licensed under the Apache License, Version 2.0 or +// the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use crate::error::EbpfError; + +#[cfg(not(target_os = "windows"))] +extern crate libc; +#[cfg(not(target_os = "windows"))] +use libc::c_void; + +#[cfg(target_os = "windows")] +use winapi::{ + ctypes::c_void, + shared::minwindef, + um::{ + errhandlingapi::GetLastError, + memoryapi::{VirtualAlloc, VirtualFree, VirtualProtect}, + sysinfoapi::{GetSystemInfo, SYSTEM_INFO}, + winnt, + }, +}; + +#[cfg(not(target_os = "windows"))] +macro_rules! libc_error_guard { + (succeeded?, mmap, $addr:expr, $($arg:expr),*) => {{ + *$addr = libc::mmap(*$addr, $($arg),*); + *$addr != libc::MAP_FAILED + }}; + (succeeded?, $function:ident, $($arg:expr),*) => { + libc::$function($($arg),*) == 0 + }; + ($function:ident, $($arg:expr),* $(,)?) => {{ + const RETRY_COUNT: usize = 3; + for i in 0..RETRY_COUNT { + if libc_error_guard!(succeeded?, $function, $($arg),*) { + break; + } else if i.saturating_add(1) == RETRY_COUNT { + let args = vec![$(format!("{:?}", $arg)),*]; + #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))] + let errno = *libc::__error(); + #[cfg(any(target_os = "android", target_os = "netbsd", target_os = "openbsd"))] + let errno = *libc::__errno(); + #[cfg(target_os = "linux")] + let errno = *libc::__errno_location(); + return Err(EbpfError::LibcInvocationFailed(stringify!($function), args, errno)); + } + } + }}; +} + +#[cfg(target_os = "windows")] +macro_rules! winapi_error_guard { + (succeeded?, VirtualAlloc, $addr:expr, $($arg:expr),*) => {{ + *$addr = VirtualAlloc(*$addr, $($arg),*); + !(*$addr).is_null() + }}; + (succeeded?, $function:ident, $($arg:expr),*) => { + $function($($arg),*) != 0 + }; + ($function:ident, $($arg:expr),* $(,)?) => {{ + if !winapi_error_guard!(succeeded?, $function, $($arg),*) { + let args = vec![$(format!("{:?}", $arg)),*]; + let errno = GetLastError(); + return Err(EbpfError::LibcInvocationFailed(stringify!($function), args, errno as i32)); + } + }}; +} + +pub fn get_system_page_size() -> usize { + #[cfg(not(target_os = "windows"))] + unsafe { + libc::sysconf(libc::_SC_PAGESIZE) as usize + } + #[cfg(target_os = "windows")] + unsafe { + let mut system_info: SYSTEM_INFO = std::mem::zeroed(); + GetSystemInfo(&mut system_info); + system_info.dwPageSize as usize + } +} + +pub fn round_to_page_size(value: usize, page_size: usize) -> usize { + value + .saturating_add(page_size) + .saturating_sub(1) + .saturating_div(page_size) + .saturating_mul(page_size) +} + +pub unsafe fn allocate_pages(size_in_bytes: usize) -> Result<*mut u8, EbpfError> { + let mut raw: *mut c_void = std::ptr::null_mut(); + #[cfg(not(target_os = "windows"))] + libc_error_guard!( + mmap, + &mut raw, + size_in_bytes, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_ANONYMOUS | libc::MAP_PRIVATE, + 0, + 0, + ); + #[cfg(target_os = "windows")] + winapi_error_guard!( + VirtualAlloc, + &mut raw, + size_in_bytes, + winnt::MEM_RESERVE | winnt::MEM_COMMIT, + winnt::PAGE_READWRITE, + ); + Ok(raw as *mut u8) +} + +pub unsafe fn free_pages(raw: *mut u8, size_in_bytes: usize) -> Result<(), EbpfError> { + #[cfg(not(target_os = "windows"))] + libc_error_guard!(munmap, raw as *mut _, size_in_bytes); + #[cfg(target_os = "windows")] + winapi_error_guard!( + VirtualFree, + raw as *mut _, + size_in_bytes, + winnt::MEM_RELEASE, // winnt::MEM_DECOMMIT + ); + Ok(()) +} + +pub unsafe fn protect_pages( + raw: *mut u8, + size_in_bytes: usize, + executable_flag: bool, +) -> Result<(), EbpfError> { + #[cfg(not(target_os = "windows"))] + { + libc_error_guard!( + mprotect, + raw as *mut _, + size_in_bytes, + if executable_flag { + libc::PROT_EXEC | libc::PROT_READ + } else { + libc::PROT_READ + }, + ); + } + #[cfg(target_os = "windows")] + { + let mut old: minwindef::DWORD = 0; + let ptr_old: *mut minwindef::DWORD = &mut old; + winapi_error_guard!( + VirtualProtect, + raw as *mut _, + size_in_bytes, + if executable_flag { + winnt::PAGE_EXECUTE_READ + } else { + winnt::PAGE_READONLY + }, + ptr_old, + ); + } + Ok(()) +}