Improve libafl_qemu snapshots (#484)
* mprotect * expose EnumIter * thread safe mem snapshot * update qemu hash * clippy * child helpers * fixes * fix build * fix dep
This commit is contained in:
parent
6bfbdd6318
commit
63d89463a3
@ -60,7 +60,7 @@ num_enum = { version = "0.5.4", default-features = false }
|
||||
typed-builder = "0.9.1" # Implement the builder pattern at compiletime
|
||||
ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown
|
||||
intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] }
|
||||
backtrace = {version = "0.3.62", optional = true} # Used to get the stacktrace in StacktraceObserver
|
||||
backtrace = {version = "0.3", optional = true} # Used to get the stacktrace in StacktraceObserver
|
||||
|
||||
serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] }
|
||||
miniz_oxide = { version = "0.5", optional = true}
|
||||
|
@ -36,7 +36,7 @@ capstone = "0.10.0"
|
||||
color-backtrace ={ version = "0.5", features = [ "resolve-modules" ] }
|
||||
termcolor = "1.1.2"
|
||||
serde = "1.0"
|
||||
backtrace = { version = "0.3.58", default-features = false, features = ["std", "serde"] }
|
||||
backtrace = { version = "0.3", default-features = false, features = ["std", "serde"] }
|
||||
num-traits = "0.2.14"
|
||||
ahash = "0.7"
|
||||
paste = "1.0"
|
||||
|
@ -34,7 +34,9 @@ goblin = "0.4.2"
|
||||
libc = "0.2"
|
||||
strum = "0.21"
|
||||
strum_macros = "0.21"
|
||||
syscall-numbers = "2.0.0"
|
||||
syscall-numbers = "2.0"
|
||||
bio = "0.39"
|
||||
thread_local = "1.1.3"
|
||||
#pyo3 = { version = "0.15", features = ["extension-module"], optional = true }
|
||||
pyo3 = { version = "0.15", optional = true }
|
||||
|
||||
|
@ -3,7 +3,7 @@ use which::which;
|
||||
|
||||
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
|
||||
const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
|
||||
const QEMU_REVISION: &str = "fa2b9c4a25f548f15b3d1b1afcfdb75cc7165f9a";
|
||||
const QEMU_REVISION: &str = "152fdbe024493f31e60060714caee3b90fdf3d9e";
|
||||
|
||||
fn build_dep_check(tools: &[&str]) {
|
||||
for tool in tools {
|
||||
@ -221,7 +221,6 @@ fn main() {
|
||||
"--disable-vvfat",
|
||||
"--disable-xen",
|
||||
"--disable-xen-pci-passthrough",
|
||||
"--disable-xfsctl",
|
||||
])
|
||||
.status()
|
||||
.expect("Configure failed");
|
||||
@ -248,7 +247,7 @@ fn main() {
|
||||
for dir in &[
|
||||
build_dir.join("libcommon.fa.p"),
|
||||
build_dir.join(&format!("libqemu-{}-linux-user.fa.p", cpu_target)),
|
||||
build_dir.join("libcommon-user.fa.p"),
|
||||
//build_dir.join("libcommon-user.fa.p"),
|
||||
//build_dir.join("libqemuutil.a.p"),
|
||||
//build_dir.join("libqom.fa.p"),
|
||||
//build_dir.join("libhwcore.fa.p"),
|
||||
|
@ -1,5 +1,5 @@
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use strum_macros::EnumIter;
|
||||
pub use strum_macros::EnumIter;
|
||||
|
||||
#[cfg(feature = "python")]
|
||||
use pyo3::prelude::*;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use strum_macros::EnumIter;
|
||||
pub use strum_macros::EnumIter;
|
||||
|
||||
#[cfg(feature = "python")]
|
||||
use pyo3::prelude::*;
|
||||
|
@ -162,8 +162,9 @@ pub fn init_with_asan(args: &mut Vec<String>, env: &mut [(String, String)]) -> E
|
||||
Emulator::new(args, env)
|
||||
}
|
||||
|
||||
pub type QemuAsanChildHelper = QemuAsanHelper;
|
||||
|
||||
#[derive(Debug)]
|
||||
// TODO intrumentation filter
|
||||
pub struct QemuAsanHelper {
|
||||
enabled: bool,
|
||||
filter: QemuInstrumentationFilter,
|
||||
@ -418,6 +419,8 @@ where
|
||||
I: Input,
|
||||
S: HasMetadata,
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||
|
||||
fn init<'a, H, OT, QT>(&self, executor: &QemuExecutor<'a, H, I, OT, QT, S>)
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
emu::Emulator,
|
||||
executor::QemuExecutor,
|
||||
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
helper::{hash_me, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
@ -78,6 +78,57 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct QemuCmpLogChildHelper {
|
||||
filter: QemuInstrumentationFilter,
|
||||
}
|
||||
|
||||
impl QemuCmpLogChildHelper {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
filter: QemuInstrumentationFilter::None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_instrumentation_filter(filter: QemuInstrumentationFilter) -> Self {
|
||||
Self { filter }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn must_instrument(&self, addr: u64) -> bool {
|
||||
self.filter.allowed(addr)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for QemuCmpLogChildHelper {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, S> QemuHelper<I, S> for QemuCmpLogChildHelper
|
||||
where
|
||||
I: Input,
|
||||
S: HasMetadata,
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||
|
||||
fn init<'a, H, OT, QT>(&self, executor: &QemuExecutor<'a, H, I, OT, QT, S>)
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
OT: ObserversTuple<I, S>,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
executor.hook_cmp_generation(gen_hashed_cmp_ids::<I, QT, S>);
|
||||
executor.emulator().set_exec_cmp8_hook(trace_cmp8_cmplog);
|
||||
executor.emulator().set_exec_cmp4_hook(trace_cmp4_cmplog);
|
||||
executor.emulator().set_exec_cmp2_hook(trace_cmp2_cmplog);
|
||||
executor.emulator().set_exec_cmp1_hook(trace_cmp1_cmplog);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_unique_cmp_ids<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
@ -110,6 +161,26 @@ where
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn gen_hashed_cmp_ids<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
_state: &mut S,
|
||||
pc: u64,
|
||||
_size: usize,
|
||||
) -> Option<u64>
|
||||
where
|
||||
S: HasMetadata,
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
if let Some(h) = helpers.match_first_type::<QemuCmpLogChildHelper>() {
|
||||
if !h.must_instrument(pc) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(hash_me(pc))
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_cmp1_cmplog(id: u64, v0: u8, v1: u8) {
|
||||
unsafe {
|
||||
__libafl_targets_cmplog_instructions(id as usize, 1, u64::from(v0), u64::from(v1));
|
||||
|
@ -1,13 +1,15 @@
|
||||
use hashbrown::{hash_map::Entry, HashMap};
|
||||
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
||||
pub use libafl_targets::{EDGES_MAP, EDGES_MAP_SIZE, MAX_EDGES_NUM};
|
||||
pub use libafl_targets::{
|
||||
edges_max_num, EDGES_MAP, EDGES_MAP_PTR, EDGES_MAP_PTR_SIZE, EDGES_MAP_SIZE, MAX_EDGES_NUM,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{cell::UnsafeCell, cmp::max};
|
||||
|
||||
use crate::{
|
||||
emu::Emulator,
|
||||
executor::QemuExecutor,
|
||||
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
helper::{hash_me, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
@ -74,15 +76,58 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
thread_local!(static PREV_LOC : UnsafeCell<u64> = UnsafeCell::new(0));
|
||||
pub type QemuEdgeCoverageWithBlocksHelper = QemuEdgeCoverageChildHelper;
|
||||
|
||||
fn hash_me(mut x: u64) -> u64 {
|
||||
x = (x.overflowing_shr(16).0 ^ x).overflowing_mul(0x45d9f3b).0;
|
||||
x = (x.overflowing_shr(16).0 ^ x).overflowing_mul(0x45d9f3b).0;
|
||||
x = (x.overflowing_shr(16).0 ^ x) ^ x;
|
||||
x
|
||||
#[derive(Debug)]
|
||||
pub struct QemuEdgeCoverageChildHelper {
|
||||
filter: QemuInstrumentationFilter,
|
||||
}
|
||||
|
||||
impl QemuEdgeCoverageChildHelper {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
filter: QemuInstrumentationFilter::None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_instrumentation_filter(filter: QemuInstrumentationFilter) -> Self {
|
||||
Self { filter }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn must_instrument(&self, addr: u64) -> bool {
|
||||
self.filter.allowed(addr)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for QemuEdgeCoverageChildHelper {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, S> QemuHelper<I, S> for QemuEdgeCoverageChildHelper
|
||||
where
|
||||
I: Input,
|
||||
S: HasMetadata,
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||
|
||||
fn init<'a, H, OT, QT>(&self, executor: &QemuExecutor<'a, H, I, OT, QT, S>)
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
OT: ObserversTuple<I, S>,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
executor.hook_edge_generation(gen_unique_edge_ids::<I, QT, S>);
|
||||
executor.emulator().set_exec_edge_hook(trace_edge_hitcount);
|
||||
}
|
||||
}
|
||||
|
||||
thread_local!(static PREV_LOC : UnsafeCell<u64> = UnsafeCell::new(0));
|
||||
|
||||
pub fn gen_unique_edge_ids<I, QT, S>(
|
||||
_emulator: &Emulator,
|
||||
helpers: &mut QT,
|
||||
@ -140,7 +185,7 @@ where
|
||||
I: Input,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
if let Some(h) = helpers.match_first_type::<QemuEdgeCoverageHelper>() {
|
||||
if let Some(h) = helpers.match_first_type::<QemuEdgeCoverageChildHelper>() {
|
||||
if !h.must_instrument(src) && !h.must_instrument(dest) {
|
||||
return None;
|
||||
}
|
||||
@ -181,8 +226,9 @@ pub fn gen_hashed_block_ids<I, QT, S>(
|
||||
pub extern "C" fn trace_block_transition_hitcount(id: u64) {
|
||||
unsafe {
|
||||
PREV_LOC.with(|prev_loc| {
|
||||
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_SIZE - 1);
|
||||
EDGES_MAP[x] = EDGES_MAP[x].wrapping_add(1);
|
||||
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_SIZE - 1);
|
||||
let entry = EDGES_MAP_PTR.add(x);
|
||||
*entry = (*entry).wrapping_add(1);
|
||||
*prev_loc.get() = id.overflowing_shr(1).0;
|
||||
});
|
||||
}
|
||||
@ -191,8 +237,9 @@ pub extern "C" fn trace_block_transition_hitcount(id: u64) {
|
||||
pub extern "C" fn trace_block_transition_single(id: u64) {
|
||||
unsafe {
|
||||
PREV_LOC.with(|prev_loc| {
|
||||
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_SIZE - 1);
|
||||
EDGES_MAP[x] = 1;
|
||||
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_SIZE - 1);
|
||||
let entry = EDGES_MAP_PTR.add(x);
|
||||
*entry = 1;
|
||||
*prev_loc.get() = id.overflowing_shr(1).0;
|
||||
});
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ use pyo3::{prelude::*, PyIterProtocol};
|
||||
|
||||
pub const SKIP_EXEC_HOOK: u64 = u64::MAX;
|
||||
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter, PartialEq)]
|
||||
#[repr(i32)]
|
||||
pub enum MmapPerms {
|
||||
None = 0,
|
||||
@ -201,7 +201,7 @@ extern "C" {
|
||||
fn target_mmap(start: u64, len: u64, target_prot: i32, flags: i32, fd: i32, offset: u64)
|
||||
-> u64;
|
||||
|
||||
/// int target_mprotect(abi_ulong start, abi_ulong len, int prot);
|
||||
/// int target_mprotect(abi_ulong start, abi_ulong len, int prot)
|
||||
fn target_mprotect(start: u64, len: u64, target_prot: i32) -> i32;
|
||||
|
||||
/// int target_munmap(abi_ulong start, abi_ulong len)
|
||||
|
@ -11,6 +11,8 @@ pub trait QemuHelper<I, S>: 'static + Debug
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = true;
|
||||
|
||||
fn init<'a, H, OT, QT>(&self, _executor: &QemuExecutor<'a, H, I, OT, QT, S>)
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
@ -114,3 +116,11 @@ impl QemuInstrumentationFilter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn hash_me(mut x: u64) -> u64 {
|
||||
x = (x.overflowing_shr(16).0 ^ x).overflowing_mul(0x45d9f3b).0;
|
||||
x = (x.overflowing_shr(16).0 ^ x).overflowing_mul(0x45d9f3b).0;
|
||||
x = (x.overflowing_shr(16).0 ^ x) ^ x;
|
||||
x
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use strum_macros::EnumIter;
|
||||
pub use strum_macros::EnumIter;
|
||||
|
||||
#[cfg(feature = "python")]
|
||||
use pyo3::prelude::*;
|
||||
|
@ -1,11 +1,17 @@
|
||||
use bio::data_structures::interval_tree::IntervalTree;
|
||||
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
||||
use std::collections::HashMap;
|
||||
use std::{
|
||||
cell::UnsafeCell,
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Mutex,
|
||||
};
|
||||
use thread_local::ThreadLocal;
|
||||
|
||||
use crate::{
|
||||
emu::Emulator,
|
||||
emu::{Emulator, MmapPerms},
|
||||
executor::QemuExecutor,
|
||||
helper::{QemuHelper, QemuHelperTuple},
|
||||
GuestAddr, SYS_mmap, SYS_mremap,
|
||||
GuestAddr, SYS_mmap, SYS_mprotect, SYS_mremap,
|
||||
};
|
||||
|
||||
pub const SNAPSHOT_PAGE_SIZE: usize = 4096;
|
||||
@ -13,19 +19,32 @@ pub const SNAPSHOT_PAGE_SIZE: usize = 4096;
|
||||
#[derive(Debug)]
|
||||
pub struct SnapshotPageInfo {
|
||||
pub addr: GuestAddr,
|
||||
pub dirty: bool,
|
||||
pub data: [u8; SNAPSHOT_PAGE_SIZE],
|
||||
pub perms: MmapPerms,
|
||||
pub private: bool,
|
||||
pub data: Option<Box<[u8; SNAPSHOT_PAGE_SIZE]>>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct SnapshotAccessInfo {
|
||||
pub access_cache: [GuestAddr; 4],
|
||||
pub access_cache_idx: usize,
|
||||
pub dirty: HashSet<GuestAddr>,
|
||||
}
|
||||
|
||||
impl SnapshotAccessInfo {
|
||||
pub fn clear(&mut self) {
|
||||
self.access_cache_idx = 0;
|
||||
self.access_cache = [GuestAddr::MAX; 4];
|
||||
self.dirty.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
// TODO be thread-safe maybe with https://amanieu.github.io/thread_local-rs/thread_local/index.html
|
||||
pub struct QemuSnapshotHelper {
|
||||
pub access_cache: [GuestAddr; 4],
|
||||
pub access_cache_idx: usize,
|
||||
pub accesses: ThreadLocal<UnsafeCell<SnapshotAccessInfo>>,
|
||||
pub new_maps: Mutex<IntervalTree<GuestAddr, Option<MmapPerms>>>,
|
||||
pub pages: HashMap<GuestAddr, SnapshotPageInfo>,
|
||||
pub dirty: Vec<GuestAddr>,
|
||||
pub brk: GuestAddr,
|
||||
pub new_maps: Vec<(GuestAddr, usize)>,
|
||||
pub empty: bool,
|
||||
}
|
||||
|
||||
@ -33,32 +52,33 @@ impl QemuSnapshotHelper {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
access_cache: [GuestAddr::MAX; 4],
|
||||
access_cache_idx: 0,
|
||||
accesses: ThreadLocal::new(),
|
||||
new_maps: Mutex::new(IntervalTree::new()),
|
||||
pages: HashMap::default(),
|
||||
dirty: vec![],
|
||||
brk: 0,
|
||||
new_maps: vec![],
|
||||
empty: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::uninit_assumed_init)]
|
||||
pub fn snapshot(&mut self, emulator: &Emulator) {
|
||||
self.brk = emulator.get_brk();
|
||||
self.pages.clear();
|
||||
for map in emulator.mappings() {
|
||||
// TODO track all the pages OR track mproctect
|
||||
if !map.flags().is_w() {
|
||||
continue;
|
||||
}
|
||||
let mut addr = map.start();
|
||||
while addr < map.end() {
|
||||
let mut info = SnapshotPageInfo {
|
||||
addr,
|
||||
dirty: false,
|
||||
data: [0; SNAPSHOT_PAGE_SIZE],
|
||||
perms: map.flags(),
|
||||
private: map.is_priv(),
|
||||
data: None,
|
||||
};
|
||||
unsafe { emulator.read_mem(addr, &mut info.data) };
|
||||
if map.flags().is_w() {
|
||||
unsafe {
|
||||
info.data = Some(Box::new(core::mem::MaybeUninit::uninit().assume_init()));
|
||||
emulator.read_mem(addr, &mut info.data.as_mut().unwrap()[..]);
|
||||
}
|
||||
}
|
||||
self.pages.insert(addr, info);
|
||||
addr += SNAPSHOT_PAGE_SIZE as GuestAddr;
|
||||
}
|
||||
@ -67,22 +87,20 @@ impl QemuSnapshotHelper {
|
||||
}
|
||||
|
||||
pub fn page_access(&mut self, page: GuestAddr) {
|
||||
if self.access_cache[0] == page
|
||||
|| self.access_cache[1] == page
|
||||
|| self.access_cache[2] == page
|
||||
|| self.access_cache[3] == page
|
||||
unsafe {
|
||||
let acc = self.accesses.get_or_default().get();
|
||||
if (*acc).access_cache[0] == page
|
||||
|| (*acc).access_cache[1] == page
|
||||
|| (*acc).access_cache[2] == page
|
||||
|| (*acc).access_cache[3] == page
|
||||
{
|
||||
return;
|
||||
}
|
||||
self.access_cache[self.access_cache_idx] = page;
|
||||
self.access_cache_idx = (self.access_cache_idx + 1) & 3;
|
||||
if let Some(info) = self.pages.get_mut(&page) {
|
||||
if info.dirty {
|
||||
return;
|
||||
let idx = (*acc).access_cache_idx;
|
||||
(*acc).access_cache[idx] = page;
|
||||
(*acc).access_cache_idx = (idx + 1) & 3;
|
||||
(*acc).dirty.insert(page);
|
||||
}
|
||||
info.dirty = true;
|
||||
}
|
||||
self.dirty.push(page);
|
||||
}
|
||||
|
||||
pub fn access(&mut self, addr: GuestAddr, size: usize) {
|
||||
@ -96,27 +114,62 @@ impl QemuSnapshotHelper {
|
||||
}
|
||||
|
||||
pub fn reset(&mut self, emulator: &Emulator) {
|
||||
self.access_cache = [GuestAddr::MAX; 4];
|
||||
self.access_cache_idx = 0;
|
||||
while let Some(page) = self.dirty.pop() {
|
||||
if let Some(info) = self.pages.get_mut(&page) {
|
||||
unsafe { emulator.write_mem(page, &info.data) };
|
||||
info.dirty = false;
|
||||
self.reset_maps(emulator);
|
||||
for acc in self.accesses.iter_mut() {
|
||||
for page in unsafe { &(*acc.get()).dirty } {
|
||||
if let Some(info) = self.pages.get_mut(page) {
|
||||
// TODO avoid duplicated memcpy
|
||||
if let Some(data) = info.data.as_ref() {
|
||||
unsafe { emulator.write_mem(*page, &data[..]) };
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe { (*acc.get()).clear() };
|
||||
}
|
||||
emulator.set_brk(self.brk);
|
||||
self.reset_maps(emulator);
|
||||
}
|
||||
|
||||
pub fn add_mapped(&mut self, start: GuestAddr, size: usize) {
|
||||
self.new_maps.push((start, size));
|
||||
pub fn add_mapped(&mut self, start: GuestAddr, mut size: usize, perms: Option<MmapPerms>) {
|
||||
if size % SNAPSHOT_PAGE_SIZE != 0 {
|
||||
size = size + (SNAPSHOT_PAGE_SIZE - size % SNAPSHOT_PAGE_SIZE);
|
||||
}
|
||||
self.new_maps
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(start..start + (size as GuestAddr), perms);
|
||||
}
|
||||
|
||||
pub fn reset_maps(&mut self, emulator: &Emulator) {
|
||||
for (addr, size) in &self.new_maps {
|
||||
drop(emulator.unmap(*addr, *size));
|
||||
let new_maps = self.new_maps.get_mut().unwrap();
|
||||
for r in new_maps.find(0..GuestAddr::MAX) {
|
||||
let addr = r.interval().start;
|
||||
let end = r.interval().end;
|
||||
let perms = r.data();
|
||||
let mut page = addr & (SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
|
||||
let mut prev = None;
|
||||
while page < end {
|
||||
if let Some(info) = self.pages.get(&page) {
|
||||
if let Some((addr, size)) = prev {
|
||||
drop(emulator.unmap(addr, size));
|
||||
}
|
||||
self.new_maps.clear();
|
||||
prev = None;
|
||||
if let Some(p) = perms {
|
||||
if info.perms != *p {
|
||||
drop(emulator.mprotect(page, SNAPSHOT_PAGE_SIZE, info.perms));
|
||||
}
|
||||
}
|
||||
} else if let Some((_, size)) = &mut prev {
|
||||
*size += SNAPSHOT_PAGE_SIZE;
|
||||
} else {
|
||||
prev = Some((page, SNAPSHOT_PAGE_SIZE));
|
||||
}
|
||||
page += SNAPSHOT_PAGE_SIZE as GuestAddr;
|
||||
}
|
||||
if let Some((addr, size)) = prev {
|
||||
drop(emulator.unmap(addr, size));
|
||||
}
|
||||
}
|
||||
*new_maps = IntervalTree::new();
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,15 +315,24 @@ where
|
||||
return result;
|
||||
}
|
||||
if i64::from(sys_num) == SYS_mmap {
|
||||
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
h.add_mapped(result as GuestAddr, a1 as usize);
|
||||
h.add_mapped(result as GuestAddr, a1 as usize, Some(prot));
|
||||
}
|
||||
} else if i64::from(sys_num) == SYS_mremap {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
h.add_mapped(a0 as GuestAddr, a2 as usize);
|
||||
h.add_mapped(result as GuestAddr, a2 as usize, None);
|
||||
} else if i64::from(sys_num) == SYS_mprotect {
|
||||
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||
let h = helpers
|
||||
.match_first_type_mut::<QemuSnapshotHelper>()
|
||||
.unwrap();
|
||||
h.add_mapped(a0 as GuestAddr, a2 as usize, Some(prot));
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use strum_macros::EnumIter;
|
||||
pub use strum_macros::EnumIter;
|
||||
|
||||
#[cfg(feature = "python")]
|
||||
use pyo3::prelude::*;
|
||||
|
Loading…
x
Reference in New Issue
Block a user