krusty
This commit is contained in:
parent
c6694a5e29
commit
3f6ffeb573
|
@ -6,6 +6,12 @@ version = "1.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.71"
|
||||
|
@ -27,6 +33,7 @@ name = "waterboxhost"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"page_size",
|
||||
"winapi",
|
||||
|
|
|
@ -10,9 +10,10 @@ publish = false
|
|||
[dependencies]
|
||||
bitflags = "1.2.1"
|
||||
page_size = "0.4.2"
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3.8", features = ["memoryapi", "handleapi", "errhandlingapi"] }
|
||||
winapi = { version = "0.3.8", features = ["memoryapi", "handleapi", "errhandlingapi", "winnt"] }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2.71"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod pageblock;
|
||||
mod pal;
|
||||
mod tripguard;
|
||||
|
||||
use pageblock::PageBlock;
|
||||
use bitflags::bitflags;
|
||||
|
@ -18,7 +19,6 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
enum Snapshot {
|
||||
None,
|
||||
ZeroFilled,
|
||||
|
|
|
@ -15,7 +15,7 @@ impl PageBlock {
|
|||
panic!("PageBlock could not allocate memory!");
|
||||
} else {
|
||||
PageBlock {
|
||||
ptr: NonNull::new_unchecked(ptr as *mut u8)
|
||||
ptr: NonNull::new_unchecked(ptr as *mut u8),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,6 @@ unsafe fn free(ptr: *mut c_void) -> bool {
|
|||
fn basic_test() {
|
||||
let mut s = PageBlock::new();
|
||||
|
||||
|
||||
for x in s.slice().iter() {
|
||||
assert!(*x == 0);
|
||||
}
|
||||
|
|
|
@ -1,27 +1,40 @@
|
|||
|
||||
static global_data = Mutex::new(GlobalData {
|
||||
initialized: false,
|
||||
activeBlocks: Vec::new(),
|
||||
});
|
||||
use std::ptr::null_mut;
|
||||
use super::MemoryBlock;
|
||||
use std::sync::Mutex;
|
||||
use crate::*;
|
||||
use super::*;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
lazy_static! {
|
||||
static ref global_data: Mutex<GlobalData> = Mutex::new(GlobalData {
|
||||
initialized: false,
|
||||
active_blocks: Vec::new(),
|
||||
});
|
||||
}
|
||||
|
||||
struct GlobalData {
|
||||
initialized: bool,
|
||||
activeBlocks: Vec<*mut MemoryBlock>,
|
||||
active_blocks: Vec<MemoryBlockRef>,
|
||||
}
|
||||
struct MemoryBlockRef(*mut MemoryBlock);
|
||||
unsafe impl Send for MemoryBlockRef {
|
||||
|
||||
}
|
||||
|
||||
pub unsafe fn register(block: *mut MemoryBlock) {
|
||||
unsafe fn register(block: *mut MemoryBlock) {
|
||||
let mut data = global_data.lock().unwrap();
|
||||
if !data.initialized {
|
||||
initialize();
|
||||
data.initialized = true;
|
||||
}
|
||||
data.activeBlocks.push(block);
|
||||
data.active_blocks.push(MemoryBlockRef(block));
|
||||
}
|
||||
|
||||
pub unsafe fn unregister(block: *mut MemoryBlock) {
|
||||
unsafe fn unregister(block: *mut MemoryBlock) {
|
||||
let mut data = global_data.lock().unwrap();
|
||||
let pos = data.activeBlocks.into_iter().position(|x| x == block).unwrap();
|
||||
data.activeBlocks.remove(pos);
|
||||
let pos = data.active_blocks.iter().position(|x| x.0 == block).unwrap();
|
||||
data.active_blocks.remove(pos);
|
||||
}
|
||||
|
||||
enum TripResult {
|
||||
|
@ -30,19 +43,102 @@ enum TripResult {
|
|||
}
|
||||
|
||||
unsafe fn trip(addr: usize) -> TripResult {
|
||||
let mut data = global_data.lock().unwrap();
|
||||
let mut memoryBlock = match data.activeBlocks
|
||||
.into_iter()
|
||||
.find(|x| addr >= x.start && addr < x.end) {
|
||||
Some(x) => x,
|
||||
None => return NotHandled,
|
||||
}
|
||||
let pageStartAddr = addr & ~PAGEMASK;
|
||||
let mut page = &mut memoryBlock.pages[(addr - memoryBlock.start) >> PAGESHIFT];
|
||||
let data = global_data.lock().unwrap();
|
||||
let memory_block = match data.active_blocks
|
||||
.iter()
|
||||
.find(|x| addr >= (*x.0).start && addr < (*x.0).end) {
|
||||
Some(x) => &mut *x.0,
|
||||
None => return TripResult::NotHandled,
|
||||
};
|
||||
let page_start_addr = addr & !PAGEMASK;
|
||||
let page = &mut memory_block.pages[(addr - memory_block.start) >> PAGESHIFT];
|
||||
if !page.flags.contains(PageFlags::W) {
|
||||
NotHandled
|
||||
return TripResult::NotHandled
|
||||
}
|
||||
if memoryBlock.sealed && page.snapshot == Snapshot::None {
|
||||
if memory_block.sealed && match page.snapshot { Snapshot::None => true, _ => false } {
|
||||
// take snapshot now
|
||||
let mut snapshot = PageBlock::new();
|
||||
let src = std::slice::from_raw_parts(page_start_addr as *const u8, PAGESIZE);
|
||||
let dst = snapshot.slice_mut();
|
||||
dst.copy_from_slice(src);
|
||||
page.snapshot = Snapshot::Data(snapshot);
|
||||
}
|
||||
page.flags.insert(PageFlags::DIRTY);
|
||||
let new_prot = if page.flags.contains(PageFlags::X) { pal::Protection::RWX } else { pal::Protection::RW };
|
||||
assert!(pal::protect(page_start_addr, PAGESIZE, new_prot));
|
||||
TripResult::Handled
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn initialize() {
|
||||
use winapi::um::errhandlingapi::*;
|
||||
use winapi::um::winnt::*;
|
||||
use winapi::vc::excpt::*;
|
||||
|
||||
unsafe extern "system" fn handler(p_info: *mut EXCEPTION_POINTERS) -> i32 {
|
||||
let p_record = &mut *(*p_info).ExceptionRecord;
|
||||
let flags = p_record.ExceptionInformation[0];
|
||||
if p_record.ExceptionCode != STATUS_ACCESS_VIOLATION // only trigger on access violations...
|
||||
|| (flags & 1) != 0 { // ...due to a write attempts
|
||||
return EXCEPTION_CONTINUE_SEARCH
|
||||
}
|
||||
let fault_address = p_record.ExceptionInformation[1] as usize;
|
||||
match trip(fault_address) {
|
||||
TripResult::Handled => EXCEPTION_CONTINUE_EXECUTION,
|
||||
TripResult::NotHandled => EXCEPTION_CONTINUE_SEARCH,
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
let res = AddVectoredExceptionHandler(1 /* CALL_FIRST */, Some(handler));
|
||||
assert!(res != null_mut(), "AddVectoredExceptionHandler failed");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
type sa_handler = unsafe extern fn(i32) -> ();
|
||||
#[cfg(unix)]
|
||||
type sa_sigaction = unsafe extern fn(i32, *const siginfo_t, *const ucontext_t) -> ();
|
||||
#[cfg(unix)]
|
||||
use libc::*;
|
||||
#[cfg(unix)]
|
||||
static mut altstack: [u8; SIGSTKSZ] = [0; SIGSTKSZ];
|
||||
#[cfg(unix)]
|
||||
static mut sa_old: Option<Box<sigaction>> = None;
|
||||
#[cfg(unix)]
|
||||
fn initialize() {
|
||||
use std::mem::{transmute, zeroed};
|
||||
|
||||
unsafe extern fn handler(sig: i32, info: *const siginfo_t, ucontext: *const ucontext_t) {
|
||||
let faultAddress = (*info).si_addr() as usize;
|
||||
let write = (*ucontext).uc_mcontext.gregs[REG_ERR as usize] & 2 != 0;
|
||||
let rethrow = !write || match trip(faultAddress) {
|
||||
TripResult::NotHandled => true,
|
||||
_ => false
|
||||
};
|
||||
if rethrow {
|
||||
if sa_old.as_ref().unwrap().sa_flags & SA_SIGINFO != 0 {
|
||||
transmute::<usize, sa_sigaction>(sa_old.as_ref().unwrap().sa_sigaction)(sig, info, ucontext);
|
||||
} else {
|
||||
transmute::<usize, sa_handler>(sa_old.as_ref().unwrap().sa_sigaction)(sig);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
sa_old = Some(Box::new(zeroed::<sigaction>()));
|
||||
let ss = stack_t {
|
||||
ss_flags: 0,
|
||||
ss_sp: &mut altstack[0] as *mut u8 as *mut c_void,
|
||||
ss_size: SIGSTKSZ
|
||||
};
|
||||
assert!(sigaltstack(&ss, null_mut()) == 0, "sigaltstack failed");
|
||||
let mut sa = sigaction {
|
||||
sa_mask: zeroed::<sigset_t>(),
|
||||
sa_sigaction: transmute::<sa_sigaction, usize>(handler),
|
||||
sa_flags: SA_ONSTACK | SA_SIGINFO,
|
||||
sa_restorer: None,
|
||||
};
|
||||
sigfillset(&mut sa.sa_mask);
|
||||
assert!(sigaction(SIGSEGV, &sa, &mut **sa_old.as_mut().unwrap() as *mut sigaction) == 0, "sigaction failed");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue