This repository has been archived by the owner on Jul 11, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Extended Page Tables (EPT) Page and inline hooks.
- Two sets of EPTs across all logical processors one for the default view, and the other for the hooked view. - The MTRRs are not integrated using this way. Took the help of Matthias' code for the public version, which will help integration with the AMD hypervisor if needed. Private one might be different. - **Note**: This is needs to be tested and is completely different from the dev branch. The dev branch is just an experiment, which did not work out well. This method is more popular but needs to be modified correctly and tested. Somethings are missing and there are crashes.
- Loading branch information
Showing
15 changed files
with
1,165 additions
and
300 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
//! This module provides a safe wrapper around the system's memory validation function, typically named `MmIsAddressValid`. | ||
//! It allows checking the validity of addresses in a way that integrates with a system's memory management routines. | ||
//! The implementation uses a global atomic pointer to hold and replace the original system function with a custom hook, | ||
//! ensuring that any calls to check memory validity are routed through this custom implementation. | ||
//! Credits to Matthias: https://github.com/not-matthias/amd_hypervisor/blob/main/driver/src/hook.rs | ||
use core::{ | ||
mem, ptr, | ||
sync::atomic::{AtomicPtr, Ordering}, | ||
}; | ||
|
||
// Extern block for interfacing with LLVM intrinsic for getting the return address. | ||
extern "C" { | ||
// Links to the LLVM intrinsic to get the address of the return address. | ||
#[link_name = "llvm.addressofreturnaddress"] | ||
fn return_address() -> *const u64; | ||
} | ||
|
||
/// A global atomic pointer to hold the original `mm_is_address_valid` function. | ||
/// It's initialized to a null mutable pointer and will be set during runtime to the actual function. | ||
pub static ORIGINAL: AtomicPtr<u64> = AtomicPtr::new(ptr::null_mut()); | ||
|
||
/// A safe wrapper around the `MmIsAddressValid` function. | ||
/// | ||
/// ## Parameters | ||
/// - `ptr`: The pointer to check for validity. | ||
/// | ||
/// ## Returns | ||
/// Returns `true` if the address is valid, `false` otherwise. | ||
/// | ||
/// ## Safety | ||
/// This function assumes that the original `MmIsAddressValid` function is correctly set and points to a valid function. | ||
/// The caller must ensure this is the case to avoid undefined behavior. | ||
pub fn mm_is_address_valid(ptr: u64) -> bool { | ||
// Log the address from which `MmIsAddressValid` was called. | ||
log::info!("MmIsAddressValid called from {:#x}", unsafe { | ||
return_address().read_volatile() // Reads the return address in a volatile manner to prevent optimizations. | ||
}); | ||
|
||
// Load the original function pointer from the global atomic pointer. | ||
let fn_ptr = ORIGINAL.load(Ordering::Relaxed); // Using relaxed ordering for atomic loading. | ||
// Transmute the function pointer to the expected function type. | ||
let fn_ptr = unsafe { mem::transmute::<_, fn(u64) -> bool>(fn_ptr) }; | ||
|
||
// Call the original `MmIsAddressValid` function with the provided pointer. | ||
fn_ptr(ptr) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
//! This crate provides utilities for setting up and managing the memory paging mechanism | ||
//! for x86 architecture within a hypervisor context. Special attention is given to the | ||
//! manipulation of page table flags corresponding to different access types and page sizes. | ||
//! Credits to Matthias: https://github.com/not-matthias/amd_hypervisor/blob/main/hypervisor/src/svm/utils/paging.rs | ||
#![allow(dead_code)] // Allows for definitions that may not be used in all configurations. | ||
|
||
use x86::bits64::paging::{PDFlags, PDPTFlags, PML4Flags, PTFlags}; | ||
|
||
// Constants defining sizes for various page table entries. | ||
pub const _512GB: u64 = 512 * 1024 * 1024 * 1024; | ||
pub const _1GB: u64 = 1024 * 1024 * 1024; | ||
pub const _2MB: usize = 2 * 1024 * 1024; | ||
pub const _4KB: usize = 4 * 1024; | ||
|
||
/// `AccessType` defines the types of access that can be granted to a page in the paging structure. | ||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone)] | ||
pub enum AccessType { | ||
ReadWrite, | ||
ReadWriteExecute, | ||
} | ||
|
||
impl AccessType { | ||
/// Generates the appropriate PML4 flags for the access type. | ||
pub fn pml4_flags(self) -> PML4Flags { | ||
match self { | ||
AccessType::ReadWrite => PML4Flags::P | PML4Flags::RW | PML4Flags::US | PML4Flags::XD, | ||
AccessType::ReadWriteExecute => PML4Flags::P | PML4Flags::RW | PML4Flags::US, | ||
} | ||
} | ||
|
||
/// Generates the appropriate PDPT flags for the access type. | ||
pub fn pdpt_flags(self) -> PDPTFlags { | ||
match self { | ||
AccessType::ReadWrite => PDPTFlags::P | PDPTFlags::RW | PDPTFlags::US | PDPTFlags::XD, | ||
AccessType::ReadWriteExecute => PDPTFlags::P | PDPTFlags::RW | PDPTFlags::US, | ||
} | ||
} | ||
|
||
/// Generates the appropriate PD flags for the access type. | ||
pub fn pd_flags(self) -> PDFlags { | ||
match self { | ||
AccessType::ReadWrite => PDFlags::P | PDFlags::RW | PDFlags::US | PDFlags::XD, | ||
AccessType::ReadWriteExecute => PDFlags::P | PDFlags::RW | PDFlags::US, | ||
} | ||
} | ||
|
||
/// Generates the appropriate PT flags for the access type. | ||
pub fn pt_flags(self) -> PTFlags { | ||
match self { | ||
AccessType::ReadWrite => { | ||
PTFlags::from_iter([PTFlags::P, PTFlags::RW, PTFlags::US, PTFlags::XD]) | ||
} | ||
AccessType::ReadWriteExecute => { | ||
PTFlags::from_iter([PTFlags::P, PTFlags::RW, PTFlags::US]) | ||
} | ||
} | ||
} | ||
|
||
/// Modifies the PDFlags for a 2MB page based on the access type. | ||
pub fn modify_2mb(&self, mut flags: PDFlags) -> PDFlags { | ||
match self { | ||
AccessType::ReadWrite => { | ||
flags.insert(PDFlags::RW); // Set the ReadWrite flag. | ||
flags.insert(PDFlags::XD); // Set the Execute Disable flag. | ||
} | ||
AccessType::ReadWriteExecute => { | ||
flags.insert(PDFlags::RW); // Set the ReadWrite flag. | ||
flags.remove(PDFlags::XD); // Remove the Execute Disable flag to allow execution. | ||
} | ||
} | ||
|
||
flags // Return the modified flags. | ||
} | ||
|
||
/// Modifies the PTFlags for a 4KB page based on the access type. | ||
pub fn modify_4kb(&self, mut flags: PTFlags) -> PTFlags { | ||
match self { | ||
AccessType::ReadWrite => { | ||
flags.insert(PTFlags::RW); // Set the ReadWrite flag. | ||
flags.insert(PTFlags::XD); // Set the Execute Disable flag. | ||
} | ||
AccessType::ReadWriteExecute => { | ||
flags.insert(PTFlags::RW); // Set the ReadWrite flag. | ||
flags.remove(PTFlags::XD); // Remove the Execute Disable flag to allow execution. | ||
} | ||
} | ||
|
||
flags // Return the modified flags. | ||
} | ||
} |
Oops, something went wrong.