Refactor QEMU hooks (#1690)
* Rewrite QEMU Asan * fake sys * New hooks * edge cov helper * opaque raw hook * new hooks * EMulator::get * new asan * fix fuzzers * fix types * fix * fix * fix * merge fix * fix
This commit is contained in:
parent
43c9100f59
commit
f1aee3c376
@ -329,7 +329,7 @@ fn fuzz(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut hooks = QemuHooks::new(
|
let mut hooks = QemuHooks::new(
|
||||||
&emu,
|
emu.clone(),
|
||||||
tuple_list!(
|
tuple_list!(
|
||||||
QemuEdgeCoverageChildHelper::default(),
|
QemuEdgeCoverageChildHelper::default(),
|
||||||
QemuCmpLogChildHelper::default(),
|
QemuCmpLogChildHelper::default(),
|
||||||
|
@ -45,15 +45,15 @@ use libafl_bolts::{
|
|||||||
AsSlice,
|
AsSlice,
|
||||||
};
|
};
|
||||||
use libafl_qemu::{
|
use libafl_qemu::{
|
||||||
|
// asan::{init_with_asan, QemuAsanHelper},
|
||||||
cmplog::{CmpLogObserver, QemuCmpLogHelper},
|
cmplog::{CmpLogObserver, QemuCmpLogHelper},
|
||||||
//asan::{init_with_asan, QemuAsanHelper},
|
|
||||||
edges::edges_map_mut_slice,
|
edges::edges_map_mut_slice,
|
||||||
edges::QemuEdgeCoverageHelper,
|
edges::QemuEdgeCoverageHelper,
|
||||||
edges::MAX_EDGES_NUM,
|
edges::MAX_EDGES_NUM,
|
||||||
elf::EasyElf,
|
elf::EasyElf,
|
||||||
emu::Emulator,
|
|
||||||
filter_qemu_args,
|
filter_qemu_args,
|
||||||
hooks::QemuHooks,
|
hooks::QemuHooks,
|
||||||
|
Emulator,
|
||||||
GuestReg,
|
GuestReg,
|
||||||
//snapshot::QemuSnapshotHelper,
|
//snapshot::QemuSnapshotHelper,
|
||||||
MmapPerms,
|
MmapPerms,
|
||||||
@ -173,7 +173,7 @@ fn fuzz(
|
|||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
let env: Vec<(String, String)> = env::vars().collect();
|
let env: Vec<(String, String)> = env::vars().collect();
|
||||||
let emu = Emulator::new(&args, &env).unwrap();
|
let emu = Emulator::new(&args, &env).unwrap();
|
||||||
//let emu = init_with_asan(&mut args, &mut env);
|
// let (emu, asan) = init_with_asan(&mut args, &mut env).unwrap();
|
||||||
|
|
||||||
let mut elf_buffer = Vec::new();
|
let mut elf_buffer = Vec::new();
|
||||||
let elf = EasyElf::from_file(emu.binary_path(), &mut elf_buffer)?;
|
let elf = EasyElf::from_file(emu.binary_path(), &mut elf_buffer)?;
|
||||||
@ -342,11 +342,11 @@ fn fuzz(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut hooks = QemuHooks::new(
|
let mut hooks = QemuHooks::new(
|
||||||
&emu,
|
emu.clone(),
|
||||||
tuple_list!(
|
tuple_list!(
|
||||||
QemuEdgeCoverageHelper::default(),
|
QemuEdgeCoverageHelper::default(),
|
||||||
QemuCmpLogHelper::default(),
|
QemuCmpLogHelper::default(),
|
||||||
//QemuAsanHelper::default(),
|
// QemuAsanHelper::default(asan),
|
||||||
//QemuSnapshotHelper::new()
|
//QemuSnapshotHelper::new()
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -215,7 +215,10 @@ pub fn fuzz() -> Result<(), Error> {
|
|||||||
ExitKind::Ok
|
ExitKind::Ok
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut hooks = QemuHooks::new(&emu, tuple_list!(QemuEdgeCoverageChildHelper::default(),));
|
let mut hooks = QemuHooks::new(
|
||||||
|
emu.clone(),
|
||||||
|
tuple_list!(QemuEdgeCoverageChildHelper::default(),),
|
||||||
|
);
|
||||||
|
|
||||||
let mut executor = QemuForkExecutor::new(
|
let mut executor = QemuForkExecutor::new(
|
||||||
&mut hooks,
|
&mut hooks,
|
||||||
|
@ -236,7 +236,7 @@ pub fn fuzz() {
|
|||||||
coverage.set_file_name(format!("{coverage_name}-{core:03}.{coverage_extension}"));
|
coverage.set_file_name(format!("{coverage_name}-{core:03}.{coverage_extension}"));
|
||||||
|
|
||||||
let mut hooks = QemuHooks::new(
|
let mut hooks = QemuHooks::new(
|
||||||
&emu,
|
emu.clone(),
|
||||||
tuple_list!(QemuDrCovHelper::new(
|
tuple_list!(QemuDrCovHelper::new(
|
||||||
QemuInstrumentationFilter::None,
|
QemuInstrumentationFilter::None,
|
||||||
rangemap,
|
rangemap,
|
||||||
|
@ -103,11 +103,12 @@ impl<'a> Client<'a> {
|
|||||||
let mut env = self.env()?;
|
let mut env = self.env()?;
|
||||||
log::debug!("ENV: {:#?}", env);
|
log::debug!("ENV: {:#?}", env);
|
||||||
|
|
||||||
let emu = {
|
let (emu, mut asan) = {
|
||||||
if self.options.is_asan_core(core_id) {
|
if self.options.is_asan_core(core_id) {
|
||||||
init_with_asan(&mut args, &mut env)?
|
let (emu, asan) = init_with_asan(&mut args, &mut env)?;
|
||||||
|
(emu, Some(asan))
|
||||||
} else {
|
} else {
|
||||||
Emulator::new(&args, &env)?
|
(Emulator::new(&args, &env)?, None)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -136,11 +137,14 @@ impl<'a> Client<'a> {
|
|||||||
let helpers = tuple_list!(
|
let helpers = tuple_list!(
|
||||||
edge_coverage_helper,
|
edge_coverage_helper,
|
||||||
QemuCmpLogHelper::default(),
|
QemuCmpLogHelper::default(),
|
||||||
QemuAsanHelper::default(),
|
QemuAsanHelper::default(asan.take().unwrap()),
|
||||||
);
|
);
|
||||||
instance.build().run(helpers, state)
|
instance.build().run(helpers, state)
|
||||||
} else if is_asan {
|
} else if is_asan {
|
||||||
let helpers = tuple_list!(edge_coverage_helper, QemuAsanHelper::default(),);
|
let helpers = tuple_list!(
|
||||||
|
edge_coverage_helper,
|
||||||
|
QemuAsanHelper::default(asan.take().unwrap()),
|
||||||
|
);
|
||||||
instance.build().run(helpers, state)
|
instance.build().run(helpers, state)
|
||||||
} else if is_cmplog {
|
} else if is_cmplog {
|
||||||
let helpers = tuple_list!(edge_coverage_helper, QemuCmpLogHelper::default(),);
|
let helpers = tuple_list!(edge_coverage_helper, QemuCmpLogHelper::default(),);
|
||||||
|
@ -59,7 +59,7 @@ impl<'a> Instance<'a> {
|
|||||||
where
|
where
|
||||||
QT: QemuHelperTuple<ClientState>,
|
QT: QemuHelperTuple<ClientState>,
|
||||||
{
|
{
|
||||||
let mut hooks = QemuHooks::new(self.emu, helpers);
|
let mut hooks = QemuHooks::new(self.emu.clone(), helpers);
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
let edges_observer = unsafe {
|
let edges_observer = unsafe {
|
||||||
|
@ -192,7 +192,7 @@ pub fn fuzz() {
|
|||||||
// A fuzzer with feedbacks and a corpus scheduler
|
// A fuzzer with feedbacks and a corpus scheduler
|
||||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||||
|
|
||||||
let mut hooks = QemuHooks::new(&emu, tuple_list!(QemuEdgeCoverageHelper::default()));
|
let mut hooks = QemuHooks::new(emu.clone(), tuple_list!(QemuEdgeCoverageHelper::default()));
|
||||||
|
|
||||||
// Create a QEMU in-process executor
|
// Create a QEMU in-process executor
|
||||||
let mut executor = QemuExecutor::new(
|
let mut executor = QemuExecutor::new(
|
||||||
|
@ -65,6 +65,7 @@ rangemap = "1.3"
|
|||||||
log = "0.4.20"
|
log = "0.4.20"
|
||||||
addr2line = "0.21"
|
addr2line = "0.21"
|
||||||
typed-arena = "2.0"
|
typed-arena = "2.0"
|
||||||
|
paste = "1"
|
||||||
enum-map = "2.7"
|
enum-map = "2.7"
|
||||||
|
|
||||||
pyo3 = { version = "0.18", optional = true }
|
pyo3 = { version = "0.18", optional = true }
|
||||||
|
@ -32,3 +32,4 @@ json = "0.12"
|
|||||||
shell-words = "1.1"
|
shell-words = "1.1"
|
||||||
pkg-config = "0.3.26"
|
pkg-config = "0.3.26"
|
||||||
cc = "1.0"
|
cc = "1.0"
|
||||||
|
regex = "1"
|
||||||
|
@ -77,6 +77,7 @@ const WRAPPER_HEADER: &str = r#"
|
|||||||
#include "qemu/plugin-memory.h"
|
#include "qemu/plugin-memory.h"
|
||||||
|
|
||||||
#include "libafl_extras/exit.h"
|
#include "libafl_extras/exit.h"
|
||||||
|
#include "libafl_extras/hook.h"
|
||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@ -114,6 +115,7 @@ pub fn generate(
|
|||||||
.allowlist_type("libafl_exit_reason_kind")
|
.allowlist_type("libafl_exit_reason_kind")
|
||||||
.allowlist_type("libafl_exit_reason_sync_backdoor")
|
.allowlist_type("libafl_exit_reason_sync_backdoor")
|
||||||
.allowlist_type("libafl_exit_reason_breakpoint")
|
.allowlist_type("libafl_exit_reason_breakpoint")
|
||||||
|
.allowlist_type("Syx.*")
|
||||||
.allowlist_function("qemu_user_init")
|
.allowlist_function("qemu_user_init")
|
||||||
.allowlist_function("target_mmap")
|
.allowlist_function("target_mmap")
|
||||||
.allowlist_function("target_mprotect")
|
.allowlist_function("target_mprotect")
|
||||||
@ -128,12 +130,9 @@ pub fn generate(
|
|||||||
.allowlist_function("qemu_plugin_hwaddr_phys_addr")
|
.allowlist_function("qemu_plugin_hwaddr_phys_addr")
|
||||||
.allowlist_function("qemu_plugin_get_hwaddr")
|
.allowlist_function("qemu_plugin_get_hwaddr")
|
||||||
.allowlist_function("qemu_target_page_size")
|
.allowlist_function("qemu_target_page_size")
|
||||||
.allowlist_function("syx_snapshot_init")
|
.allowlist_function("syx_.*")
|
||||||
.allowlist_function("syx_snapshot_new")
|
|
||||||
.allowlist_function("syx_snapshot_root_restore")
|
|
||||||
.allowlist_function("syx_snapshot_dirty_list_add")
|
|
||||||
.allowlist_function("device_list_all")
|
.allowlist_function("device_list_all")
|
||||||
.allowlist_function("libafl_get_exit_reason")
|
.allowlist_function("libafl_.*")
|
||||||
.blocklist_function("main_loop_wait") // bindgen issue #1313
|
.blocklist_function("main_loop_wait") // bindgen issue #1313
|
||||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks));
|
.parse_callbacks(Box::new(bindgen::CargoCallbacks));
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ use which::which;
|
|||||||
|
|
||||||
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
|
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
|
||||||
const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
|
const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
|
||||||
const QEMU_REVISION: &str = "8db5524416b52c999459f1fe3373846bdcb23ac1";
|
const QEMU_REVISION: &str = "6a63c7f7924d3db1dfff99e7b6cf460e8fb35785";
|
||||||
|
|
||||||
fn build_dep_check(tools: &[&str]) {
|
fn build_dep_check(tools: &[&str]) {
|
||||||
for tool in tools {
|
for tool in tools {
|
||||||
|
@ -5,6 +5,7 @@ use std::{
|
|||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
use which::which;
|
use which::which;
|
||||||
|
|
||||||
mod bindings;
|
mod bindings;
|
||||||
@ -28,6 +29,13 @@ pub fn build_with_bindings(
|
|||||||
.expect("Failed to generate the bindings");
|
.expect("Failed to generate the bindings");
|
||||||
bind.write_to_file(bindings_file)
|
bind.write_to_file(bindings_file)
|
||||||
.expect("Faield to write to the bindings file");
|
.expect("Faield to write to the bindings file");
|
||||||
|
|
||||||
|
// """Fix""" the bindings here
|
||||||
|
let contents =
|
||||||
|
fs::read_to_string(bindings_file).expect("Should have been able to read the file");
|
||||||
|
let re = Regex::new("(Option<\\s*)unsafe( extern \"C\" fn\\(data: u64)").unwrap();
|
||||||
|
let replaced = re.replace_all(&contents, "$1$2");
|
||||||
|
fs::write(bindings_file, replaced.as_bytes()).expect("Unable to write file");
|
||||||
}
|
}
|
||||||
|
|
||||||
// For bindgen, the llvm version must be >= of the rust llvm version
|
// For bindgen, the llvm version must be >= of the rust llvm version
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -22,7 +22,7 @@ use crate::{
|
|||||||
calls::FullBacktraceCollector,
|
calls::FullBacktraceCollector,
|
||||||
emu::{EmuError, Emulator, MemAccessInfo, SyscallHookResult},
|
emu::{EmuError, Emulator, MemAccessInfo, SyscallHookResult},
|
||||||
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||||
hooks::QemuHooks,
|
hooks::{Hook, QemuHooks},
|
||||||
GuestAddr, Regs,
|
GuestAddr, Regs,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,6 +61,14 @@ pub enum QasanAction {
|
|||||||
SwapState,
|
SwapState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u32> for QasanAction {
|
||||||
|
type Error = num_enum::TryFromPrimitiveError<QasanAction>;
|
||||||
|
|
||||||
|
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||||
|
QasanAction::try_from(value as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, PartialEq)]
|
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, PartialEq)]
|
||||||
#[repr(i8)]
|
#[repr(i8)]
|
||||||
pub enum PoisonKind {
|
pub enum PoisonKind {
|
||||||
@ -143,7 +151,7 @@ impl AllocTreeItem {
|
|||||||
self.allocated = false;
|
self.allocated = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
use std::pin::Pin;
|
||||||
pub struct AsanGiovese {
|
pub struct AsanGiovese {
|
||||||
pub alloc_tree: Mutex<IntervalTree<GuestAddr, AllocTreeItem>>,
|
pub alloc_tree: Mutex<IntervalTree<GuestAddr, AllocTreeItem>>,
|
||||||
pub saved_tree: IntervalTree<GuestAddr, AllocTreeItem>,
|
pub saved_tree: IntervalTree<GuestAddr, AllocTreeItem>,
|
||||||
@ -163,7 +171,7 @@ impl core::fmt::Debug for AsanGiovese {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AsanGiovese {
|
impl AsanGiovese {
|
||||||
pub unsafe fn map_shadow() {
|
unsafe fn map_shadow() {
|
||||||
assert!(
|
assert!(
|
||||||
libc::mmap(
|
libc::mmap(
|
||||||
HIGH_SHADOW_ADDR,
|
HIGH_SHADOW_ADDR,
|
||||||
@ -196,6 +204,80 @@ impl AsanGiovese {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn new(emu: &Emulator) -> Pin<Box<Self>> {
|
||||||
|
let res = Self {
|
||||||
|
alloc_tree: Mutex::new(IntervalTree::new()),
|
||||||
|
saved_tree: IntervalTree::new(),
|
||||||
|
error_callback: None,
|
||||||
|
dirty_shadow: Mutex::new(HashSet::default()),
|
||||||
|
saved_shadow: HashMap::default(),
|
||||||
|
snapshot_shadow: true, // By default, track the dirty shadow pages
|
||||||
|
};
|
||||||
|
let mut boxed = Box::pin(res);
|
||||||
|
emu.add_pre_syscall_hook(boxed.as_mut(), Self::fake_syscall);
|
||||||
|
boxed
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn fake_syscall(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
sys_num: i32,
|
||||||
|
a0: GuestAddr,
|
||||||
|
a1: GuestAddr,
|
||||||
|
a2: GuestAddr,
|
||||||
|
a3: GuestAddr,
|
||||||
|
_a4: GuestAddr,
|
||||||
|
_a5: GuestAddr,
|
||||||
|
_a6: GuestAddr,
|
||||||
|
_a7: GuestAddr,
|
||||||
|
) -> SyscallHookResult {
|
||||||
|
if sys_num == QASAN_FAKESYS_NR {
|
||||||
|
let mut r = 0;
|
||||||
|
let emulator = Emulator::get().unwrap();
|
||||||
|
match QasanAction::try_from(a0).expect("Invalid QASan action number") {
|
||||||
|
QasanAction::Poison => {
|
||||||
|
self.poison(
|
||||||
|
&emulator,
|
||||||
|
a1,
|
||||||
|
a2 as usize,
|
||||||
|
PoisonKind::try_from(a3 as i8).unwrap().into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
QasanAction::UserPoison => {
|
||||||
|
self.poison(&emulator, a1, a2 as usize, PoisonKind::User.into());
|
||||||
|
}
|
||||||
|
QasanAction::UnPoison => {
|
||||||
|
Self::unpoison(&emulator, a1, a2 as usize);
|
||||||
|
}
|
||||||
|
QasanAction::IsPoison => {
|
||||||
|
if Self::is_invalid_access(&emulator, a1, a2 as usize) {
|
||||||
|
r = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QasanAction::Alloc => {
|
||||||
|
let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap();
|
||||||
|
self.allocation(pc, a1, a2);
|
||||||
|
}
|
||||||
|
QasanAction::Dealloc => {
|
||||||
|
let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap();
|
||||||
|
self.deallocation(&emulator, pc, a1);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
SyscallHookResult::new(Some(r))
|
||||||
|
} else {
|
||||||
|
SyscallHookResult::new(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_error_callback(&mut self, error_callback: AsanErrorCallback) {
|
||||||
|
self.error_callback = Some(error_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_snapshot_shadow(&mut self, snapshot_shadow: bool) {
|
||||||
|
self.snapshot_shadow = snapshot_shadow;
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_invalid_access_1(emu: &Emulator, addr: GuestAddr) -> bool {
|
pub fn is_invalid_access_1(emu: &Emulator, addr: GuestAddr) -> bool {
|
||||||
@ -357,7 +439,7 @@ impl AsanGiovese {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn unpoison_page(emu: &Emulator, page: GuestAddr) {
|
pub fn unpoison_page(emu: &Emulator, page: GuestAddr) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let h = emu.g2h::<*const c_void>(page) as isize;
|
let h = emu.g2h::<*const c_void>(page) as isize;
|
||||||
let shadow_addr = ((h >> 3) as *mut i8).offset(SHADOW_OFFSET);
|
let shadow_addr = ((h >> 3) as *mut i8).offset(SHADOW_OFFSET);
|
||||||
@ -375,30 +457,6 @@ impl AsanGiovese {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn new(snapshot_shadow: bool) -> Self {
|
|
||||||
Self {
|
|
||||||
alloc_tree: Mutex::new(IntervalTree::new()),
|
|
||||||
saved_tree: IntervalTree::new(),
|
|
||||||
error_callback: None,
|
|
||||||
dirty_shadow: Mutex::new(HashSet::default()),
|
|
||||||
saved_shadow: HashMap::default(),
|
|
||||||
snapshot_shadow,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn with_error_callback(snapshot_shadow: bool, error_callback: AsanErrorCallback) -> Self {
|
|
||||||
Self {
|
|
||||||
alloc_tree: Mutex::new(IntervalTree::new()),
|
|
||||||
saved_tree: IntervalTree::new(),
|
|
||||||
error_callback: Some(error_callback),
|
|
||||||
dirty_shadow: Mutex::new(HashSet::default()),
|
|
||||||
saved_shadow: HashMap::default(),
|
|
||||||
snapshot_shadow,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn report_or_crash(&mut self, emu: &Emulator, pc: GuestAddr, error: AsanError) {
|
pub fn report_or_crash(&mut self, emu: &Emulator, pc: GuestAddr, error: AsanError) {
|
||||||
if let Some(mut cb) = self.error_callback.take() {
|
if let Some(mut cb) = self.error_callback.take() {
|
||||||
(cb)(self, emu, pc, error);
|
(cb)(self, emu, pc, error);
|
||||||
@ -529,6 +587,15 @@ impl AsanGiovese {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn allocation(&mut self, pc: GuestAddr, start: GuestAddr, end: GuestAddr) {
|
||||||
|
self.alloc_remove(start, end);
|
||||||
|
self.alloc_insert(pc, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deallocation(&mut self, emulator: &Emulator, pc: GuestAddr, addr: GuestAddr) {
|
||||||
|
self.alloc_free(emulator, pc, addr);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn snapshot(&mut self, emu: &Emulator) {
|
pub fn snapshot(&mut self, emu: &Emulator) {
|
||||||
if self.snapshot_shadow {
|
if self.snapshot_shadow {
|
||||||
let set = self.dirty_shadow.lock().unwrap();
|
let set = self.dirty_shadow.lock().unwrap();
|
||||||
@ -599,7 +666,7 @@ static mut ASAN_INITED: bool = false;
|
|||||||
pub fn init_with_asan(
|
pub fn init_with_asan(
|
||||||
args: &mut Vec<String>,
|
args: &mut Vec<String>,
|
||||||
env: &mut [(String, String)],
|
env: &mut [(String, String)],
|
||||||
) -> Result<Emulator, EmuError> {
|
) -> Result<(Emulator, Pin<Box<AsanGiovese>>), EmuError> {
|
||||||
let current = env::current_exe().unwrap();
|
let current = env::current_exe().unwrap();
|
||||||
let asan_lib = fs::canonicalize(current)
|
let asan_lib = fs::canonicalize(current)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -644,7 +711,11 @@ pub fn init_with_asan(
|
|||||||
AsanGiovese::map_shadow();
|
AsanGiovese::map_shadow();
|
||||||
ASAN_INITED = true;
|
ASAN_INITED = true;
|
||||||
}
|
}
|
||||||
Emulator::new(args, env)
|
|
||||||
|
let emu = Emulator::new(args, env)?;
|
||||||
|
let rt = AsanGiovese::new(&emu);
|
||||||
|
|
||||||
|
Ok((emu, rt))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum QemuAsanOptions {
|
pub enum QemuAsanOptions {
|
||||||
@ -661,13 +732,26 @@ pub struct QemuAsanHelper {
|
|||||||
enabled: bool,
|
enabled: bool,
|
||||||
detect_leaks: bool,
|
detect_leaks: bool,
|
||||||
empty: bool,
|
empty: bool,
|
||||||
rt: AsanGiovese,
|
rt: Pin<Box<AsanGiovese>>,
|
||||||
filter: QemuInstrumentationFilter,
|
filter: QemuInstrumentationFilter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QemuAsanHelper {
|
impl QemuAsanHelper {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(filter: QemuInstrumentationFilter, options: QemuAsanOptions) -> Self {
|
pub fn default(rt: Pin<Box<AsanGiovese>>) -> Self {
|
||||||
|
Self::new(
|
||||||
|
rt,
|
||||||
|
QemuInstrumentationFilter::None,
|
||||||
|
QemuAsanOptions::Snapshot,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(
|
||||||
|
mut rt: Pin<Box<AsanGiovese>>,
|
||||||
|
filter: QemuInstrumentationFilter,
|
||||||
|
options: QemuAsanOptions,
|
||||||
|
) -> Self {
|
||||||
assert!(unsafe { ASAN_INITED }, "The ASan runtime is not initialized, use init_with_asan(...) instead of just Emulator::new(...)");
|
assert!(unsafe { ASAN_INITED }, "The ASan runtime is not initialized, use init_with_asan(...) instead of just Emulator::new(...)");
|
||||||
let (snapshot, detect_leaks) = match options {
|
let (snapshot, detect_leaks) = match options {
|
||||||
QemuAsanOptions::None => (false, false),
|
QemuAsanOptions::None => (false, false),
|
||||||
@ -675,17 +759,19 @@ impl QemuAsanHelper {
|
|||||||
QemuAsanOptions::DetectLeaks => (false, true),
|
QemuAsanOptions::DetectLeaks => (false, true),
|
||||||
QemuAsanOptions::SnapshotDetectLeaks => (true, true),
|
QemuAsanOptions::SnapshotDetectLeaks => (true, true),
|
||||||
};
|
};
|
||||||
|
rt.set_snapshot_shadow(snapshot);
|
||||||
Self {
|
Self {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
detect_leaks,
|
detect_leaks,
|
||||||
empty: true,
|
empty: true,
|
||||||
rt: AsanGiovese::new(snapshot),
|
rt,
|
||||||
filter,
|
filter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_error_callback(
|
pub fn with_error_callback(
|
||||||
|
mut rt: Pin<Box<AsanGiovese>>,
|
||||||
filter: QemuInstrumentationFilter,
|
filter: QemuInstrumentationFilter,
|
||||||
error_callback: AsanErrorCallback,
|
error_callback: AsanErrorCallback,
|
||||||
options: QemuAsanOptions,
|
options: QemuAsanOptions,
|
||||||
@ -697,18 +783,24 @@ impl QemuAsanHelper {
|
|||||||
QemuAsanOptions::DetectLeaks => (false, true),
|
QemuAsanOptions::DetectLeaks => (false, true),
|
||||||
QemuAsanOptions::SnapshotDetectLeaks => (true, true),
|
QemuAsanOptions::SnapshotDetectLeaks => (true, true),
|
||||||
};
|
};
|
||||||
|
rt.set_snapshot_shadow(snapshot);
|
||||||
|
rt.set_error_callback(error_callback);
|
||||||
Self {
|
Self {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
detect_leaks,
|
detect_leaks,
|
||||||
empty: true,
|
empty: true,
|
||||||
rt: AsanGiovese::with_error_callback(snapshot, error_callback),
|
rt,
|
||||||
filter,
|
filter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_asan_report(filter: QemuInstrumentationFilter, options: QemuAsanOptions) -> Self {
|
pub fn with_asan_report(
|
||||||
Self::with_error_callback(filter, Box::new(asan_report), options)
|
rt: Pin<Box<AsanGiovese>>,
|
||||||
|
filter: QemuInstrumentationFilter,
|
||||||
|
options: QemuAsanOptions,
|
||||||
|
) -> Self {
|
||||||
|
Self::with_error_callback(rt, filter, Box::new(asan_report), options)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -726,12 +818,11 @@ impl QemuAsanHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn alloc(&mut self, pc: GuestAddr, start: GuestAddr, end: GuestAddr) {
|
pub fn alloc(&mut self, pc: GuestAddr, start: GuestAddr, end: GuestAddr) {
|
||||||
self.rt.alloc_remove(start, end);
|
self.rt.allocation(pc, start, end);
|
||||||
self.rt.alloc_insert(pc, start, end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dealloc(&mut self, emulator: &Emulator, pc: GuestAddr, addr: GuestAddr) {
|
pub fn dealloc(&mut self, emulator: &Emulator, pc: GuestAddr, addr: GuestAddr) {
|
||||||
self.rt.alloc_free(emulator, pc, addr);
|
self.rt.deallocation(emulator, pc, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unused_self)]
|
#[allow(clippy::unused_self)]
|
||||||
@ -830,12 +921,6 @@ impl QemuAsanHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for QemuAsanHelper {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new(QemuInstrumentationFilter::None, QemuAsanOptions::Snapshot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasInstrumentationFilter for QemuAsanHelper {
|
impl HasInstrumentationFilter for QemuAsanHelper {
|
||||||
fn filter(&self) -> &QemuInstrumentationFilter {
|
fn filter(&self) -> &QemuInstrumentationFilter {
|
||||||
&self.filter
|
&self.filter
|
||||||
@ -852,37 +937,37 @@ where
|
|||||||
{
|
{
|
||||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||||
|
|
||||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn init_hooks<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
hooks.syscalls(qasan_fake_syscall::<QT, S>);
|
hooks.syscalls(Hook::Function(qasan_fake_syscall::<QT, S>));
|
||||||
|
|
||||||
if self.rt.error_callback.is_some() {
|
if self.rt.error_callback.is_some() {
|
||||||
hooks.crash(oncrash_asan::<QT, S>);
|
hooks.crash_function(oncrash_asan::<QT, S>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
hooks.reads(
|
hooks.reads(
|
||||||
Some(gen_readwrite_asan::<QT, S>),
|
Hook::Function(gen_readwrite_asan::<QT, S>),
|
||||||
Some(trace_read1_asan::<QT, S>),
|
Hook::Function(trace_read1_asan::<QT, S>),
|
||||||
Some(trace_read2_asan::<QT, S>),
|
Hook::Function(trace_read2_asan::<QT, S>),
|
||||||
Some(trace_read4_asan::<QT, S>),
|
Hook::Function(trace_read4_asan::<QT, S>),
|
||||||
Some(trace_read8_asan::<QT, S>),
|
Hook::Function(trace_read8_asan::<QT, S>),
|
||||||
Some(trace_read_n_asan::<QT, S>),
|
Hook::Function(trace_read_n_asan::<QT, S>),
|
||||||
);
|
);
|
||||||
|
|
||||||
hooks.writes(
|
hooks.writes(
|
||||||
Some(gen_readwrite_asan::<QT, S>),
|
Hook::Function(gen_readwrite_asan::<QT, S>),
|
||||||
Some(trace_write1_asan::<QT, S>),
|
Hook::Function(trace_write1_asan::<QT, S>),
|
||||||
Some(trace_write2_asan::<QT, S>),
|
Hook::Function(trace_write2_asan::<QT, S>),
|
||||||
Some(trace_write4_asan::<QT, S>),
|
Hook::Function(trace_write4_asan::<QT, S>),
|
||||||
Some(trace_write8_asan::<QT, S>),
|
Hook::Function(trace_write8_asan::<QT, S>),
|
||||||
Some(trace_write_n_asan::<QT, S>),
|
Hook::Function(trace_write_n_asan::<QT, S>),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -908,7 +993,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn oncrash_asan<QT, S>(hooks: &mut QemuHooks<'_, QT, S>, target_sig: i32)
|
pub fn oncrash_asan<QT, S>(hooks: &mut QemuHooks<QT, S>, target_sig: i32)
|
||||||
where
|
where
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
@ -920,7 +1005,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_readwrite_asan<QT, S>(
|
pub fn gen_readwrite_asan<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
_info: MemAccessInfo,
|
_info: MemAccessInfo,
|
||||||
@ -938,7 +1023,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_read1_asan<QT, S>(
|
pub fn trace_read1_asan<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
id: u64,
|
id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -952,7 +1037,7 @@ pub fn trace_read1_asan<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_read2_asan<QT, S>(
|
pub fn trace_read2_asan<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
id: u64,
|
id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -966,7 +1051,7 @@ pub fn trace_read2_asan<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_read4_asan<QT, S>(
|
pub fn trace_read4_asan<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
id: u64,
|
id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -980,7 +1065,7 @@ pub fn trace_read4_asan<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_read8_asan<QT, S>(
|
pub fn trace_read8_asan<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
id: u64,
|
id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -994,7 +1079,7 @@ pub fn trace_read8_asan<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_read_n_asan<QT, S>(
|
pub fn trace_read_n_asan<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
id: u64,
|
id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -1009,7 +1094,7 @@ pub fn trace_read_n_asan<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_write1_asan<QT, S>(
|
pub fn trace_write1_asan<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
id: u64,
|
id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -1023,7 +1108,7 @@ pub fn trace_write1_asan<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_write2_asan<QT, S>(
|
pub fn trace_write2_asan<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
id: u64,
|
id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -1037,7 +1122,7 @@ pub fn trace_write2_asan<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_write4_asan<QT, S>(
|
pub fn trace_write4_asan<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
id: u64,
|
id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -1051,7 +1136,7 @@ pub fn trace_write4_asan<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_write8_asan<QT, S>(
|
pub fn trace_write8_asan<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
id: u64,
|
id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -1065,7 +1150,7 @@ pub fn trace_write8_asan<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_write_n_asan<QT, S>(
|
pub fn trace_write_n_asan<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
id: u64,
|
id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -1081,17 +1166,17 @@ pub fn trace_write_n_asan<QT, S>(
|
|||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn qasan_fake_syscall<QT, S>(
|
pub fn qasan_fake_syscall<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
sys_num: i32,
|
sys_num: i32,
|
||||||
a0: u64,
|
a0: GuestAddr,
|
||||||
a1: u64,
|
a1: GuestAddr,
|
||||||
a2: u64,
|
a2: GuestAddr,
|
||||||
a3: u64,
|
_a3: GuestAddr,
|
||||||
_a4: u64,
|
_a4: GuestAddr,
|
||||||
_a5: u64,
|
_a5: GuestAddr,
|
||||||
_a6: u64,
|
_a6: GuestAddr,
|
||||||
_a7: u64,
|
_a7: GuestAddr,
|
||||||
) -> SyscallHookResult
|
) -> SyscallHookResult
|
||||||
where
|
where
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
@ -1100,42 +1185,14 @@ where
|
|||||||
if sys_num == QASAN_FAKESYS_NR {
|
if sys_num == QASAN_FAKESYS_NR {
|
||||||
let emulator = hooks.emulator().clone();
|
let emulator = hooks.emulator().clone();
|
||||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||||
let mut r = 0;
|
|
||||||
match QasanAction::try_from(a0).expect("Invalid QASan action number") {
|
match QasanAction::try_from(a0).expect("Invalid QASan action number") {
|
||||||
QasanAction::CheckLoad => {
|
QasanAction::CheckLoad => {
|
||||||
let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap();
|
let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap();
|
||||||
h.read_n(&emulator, pc, a1 as GuestAddr, a2 as usize);
|
h.read_n(&emulator, pc, a1, a2 as usize);
|
||||||
}
|
}
|
||||||
QasanAction::CheckStore => {
|
QasanAction::CheckStore => {
|
||||||
let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap();
|
let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap();
|
||||||
h.write_n(&emulator, pc, a1 as GuestAddr, a2 as usize);
|
h.write_n(&emulator, pc, a1, a2 as usize);
|
||||||
}
|
|
||||||
QasanAction::Poison => {
|
|
||||||
h.poison(
|
|
||||||
&emulator,
|
|
||||||
a1 as GuestAddr,
|
|
||||||
a2 as usize,
|
|
||||||
PoisonKind::try_from(a3 as i8).unwrap(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
QasanAction::UserPoison => {
|
|
||||||
h.poison(&emulator, a1 as GuestAddr, a2 as usize, PoisonKind::User);
|
|
||||||
}
|
|
||||||
QasanAction::UnPoison => {
|
|
||||||
h.unpoison(&emulator, a1 as GuestAddr, a2 as usize);
|
|
||||||
}
|
|
||||||
QasanAction::IsPoison => {
|
|
||||||
if h.is_poisoned(&emulator, a1 as GuestAddr, a2 as usize) {
|
|
||||||
r = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QasanAction::Alloc => {
|
|
||||||
let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap();
|
|
||||||
h.alloc(pc, a1 as GuestAddr, a2 as GuestAddr);
|
|
||||||
}
|
|
||||||
QasanAction::Dealloc => {
|
|
||||||
let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap();
|
|
||||||
h.dealloc(&emulator, pc, a1 as GuestAddr);
|
|
||||||
}
|
}
|
||||||
QasanAction::Enable => {
|
QasanAction::Enable => {
|
||||||
h.set_enabled(true);
|
h.set_enabled(true);
|
||||||
@ -1146,8 +1203,9 @@ where
|
|||||||
QasanAction::SwapState => {
|
QasanAction::SwapState => {
|
||||||
h.set_enabled(!h.enabled());
|
h.set_enabled(!h.enabled());
|
||||||
}
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
SyscallHookResult::new(Some(r))
|
SyscallHookResult::new(Some(0))
|
||||||
} else {
|
} else {
|
||||||
SyscallHookResult::new(None)
|
SyscallHookResult::new(None)
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,14 @@ use crate::{
|
|||||||
capstone,
|
capstone,
|
||||||
emu::{ArchExtras, Emulator},
|
emu::{ArchExtras, Emulator},
|
||||||
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||||
hooks::QemuHooks,
|
hooks::{Hook, QemuHooks},
|
||||||
GuestAddr,
|
GuestAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait CallTraceCollector: 'static + Debug {
|
pub trait CallTraceCollector: 'static + Debug {
|
||||||
fn on_call<QT, S>(
|
fn on_call<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
state: Option<&mut S>,
|
state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
call_len: usize,
|
call_len: usize,
|
||||||
@ -30,7 +30,7 @@ pub trait CallTraceCollector: 'static + Debug {
|
|||||||
|
|
||||||
fn on_ret<QT, S>(
|
fn on_ret<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
state: Option<&mut S>,
|
state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
ret_addr: GuestAddr,
|
ret_addr: GuestAddr,
|
||||||
@ -61,7 +61,7 @@ pub trait CallTraceCollector: 'static + Debug {
|
|||||||
pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug {
|
pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug {
|
||||||
fn on_call_all<QT, S>(
|
fn on_call_all<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
call_len: usize,
|
call_len: usize,
|
||||||
@ -71,7 +71,7 @@ pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug {
|
|||||||
|
|
||||||
fn on_ret_all<QT, S>(
|
fn on_ret_all<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
_pc: GuestAddr,
|
_pc: GuestAddr,
|
||||||
ret_addr: GuestAddr,
|
ret_addr: GuestAddr,
|
||||||
@ -97,7 +97,7 @@ pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug {
|
|||||||
impl CallTraceCollectorTuple for () {
|
impl CallTraceCollectorTuple for () {
|
||||||
fn on_call_all<QT, S>(
|
fn on_call_all<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
_hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
_pc: GuestAddr,
|
_pc: GuestAddr,
|
||||||
_call_len: usize,
|
_call_len: usize,
|
||||||
@ -109,7 +109,7 @@ impl CallTraceCollectorTuple for () {
|
|||||||
|
|
||||||
fn on_ret_all<QT, S>(
|
fn on_ret_all<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
_hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
_pc: GuestAddr,
|
_pc: GuestAddr,
|
||||||
_ret_addr: GuestAddr,
|
_ret_addr: GuestAddr,
|
||||||
@ -145,7 +145,7 @@ where
|
|||||||
{
|
{
|
||||||
fn on_call_all<QT, S>(
|
fn on_call_all<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
mut state: Option<&mut S>,
|
mut state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
call_len: usize,
|
call_len: usize,
|
||||||
@ -167,7 +167,7 @@ where
|
|||||||
|
|
||||||
fn on_ret_all<QT, S>(
|
fn on_ret_all<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
mut state: Option<&mut S>,
|
mut state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
ret_addr: GuestAddr,
|
ret_addr: GuestAddr,
|
||||||
@ -238,7 +238,7 @@ where
|
|||||||
self.filter.allowed(addr)
|
self.filter.allowed(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_ret<QT, S>(hooks: &mut QemuHooks<'_, QT, S>, state: Option<&mut S>, pc: GuestAddr)
|
fn on_ret<QT, S>(hooks: &mut QemuHooks<QT, S>, state: Option<&mut S>, pc: GuestAddr)
|
||||||
where
|
where
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
@ -267,7 +267,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn gen_blocks_calls<QT, S>(
|
fn gen_blocks_calls<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
) -> Option<u64>
|
) -> Option<u64>
|
||||||
@ -319,9 +319,8 @@ where
|
|||||||
capstone::InsnGroupType::CS_GRP_CALL => {
|
capstone::InsnGroupType::CS_GRP_CALL => {
|
||||||
let call_len = insn.bytes().len();
|
let call_len = insn.bytes().len();
|
||||||
// TODO do not use a closure, find a more efficient way to pass call_len
|
// TODO do not use a closure, find a more efficient way to pass call_len
|
||||||
let call_cb = move |hooks: &mut QemuHooks<'_, QT, S>,
|
let call_cb = Box::new(
|
||||||
state: Option<&mut S>,
|
move |hooks: &mut QemuHooks<QT, S>, state: Option<&mut S>, pc| {
|
||||||
pc| {
|
|
||||||
// eprintln!("CALL @ 0x{:#x}", pc + call_len);
|
// eprintln!("CALL @ 0x{:#x}", pc + call_len);
|
||||||
let mut collectors = if let Some(h) =
|
let mut collectors = if let Some(h) =
|
||||||
hooks.helpers_mut().match_first_type_mut::<Self>()
|
hooks.helpers_mut().match_first_type_mut::<Self>()
|
||||||
@ -342,17 +341,16 @@ where
|
|||||||
.match_first_type_mut::<Self>()
|
.match_first_type_mut::<Self>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collectors = collectors;
|
.collectors = collectors;
|
||||||
};
|
},
|
||||||
unsafe {
|
|
||||||
hooks.instruction_closure(
|
|
||||||
insn.address() as GuestAddr,
|
|
||||||
Box::new(call_cb),
|
|
||||||
false,
|
|
||||||
);
|
);
|
||||||
}
|
hooks.instruction_closure(insn.address() as GuestAddr, call_cb, false);
|
||||||
}
|
}
|
||||||
capstone::InsnGroupType::CS_GRP_RET => {
|
capstone::InsnGroupType::CS_GRP_RET => {
|
||||||
hooks.instruction(insn.address() as GuestAddr, Self::on_ret, false);
|
hooks.instruction_function(
|
||||||
|
insn.address() as GuestAddr,
|
||||||
|
Self::on_ret,
|
||||||
|
false,
|
||||||
|
);
|
||||||
break 'disasm;
|
break 'disasm;
|
||||||
}
|
}
|
||||||
capstone::InsnGroupType::CS_GRP_INVALID
|
capstone::InsnGroupType::CS_GRP_INVALID
|
||||||
@ -400,11 +398,15 @@ where
|
|||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
T: CallTraceCollectorTuple,
|
T: CallTraceCollectorTuple,
|
||||||
{
|
{
|
||||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn init_hooks<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
hooks.blocks(Some(Self::gen_blocks_calls::<QT, S>), None, None);
|
hooks.blocks(
|
||||||
|
Hook::Function(Self::gen_blocks_calls::<QT, S>),
|
||||||
|
Hook::Empty,
|
||||||
|
Hook::Empty,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_exec(&mut self, emulator: &Emulator, input: &S::Input) {
|
fn pre_exec(&mut self, emulator: &Emulator, input: &S::Input) {
|
||||||
@ -468,7 +470,7 @@ impl CallTraceCollector for OnCrashBacktraceCollector {
|
|||||||
#[allow(clippy::unnecessary_cast)]
|
#[allow(clippy::unnecessary_cast)]
|
||||||
fn on_call<QT, S>(
|
fn on_call<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
_hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
call_len: usize,
|
call_len: usize,
|
||||||
@ -482,7 +484,7 @@ impl CallTraceCollector for OnCrashBacktraceCollector {
|
|||||||
#[allow(clippy::unnecessary_cast)]
|
#[allow(clippy::unnecessary_cast)]
|
||||||
fn on_ret<QT, S>(
|
fn on_ret<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
_hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
_pc: GuestAddr,
|
_pc: GuestAddr,
|
||||||
ret_addr: GuestAddr,
|
ret_addr: GuestAddr,
|
||||||
@ -557,7 +559,7 @@ impl CallTraceCollector for FullBacktraceCollector {
|
|||||||
#[allow(clippy::unnecessary_cast)]
|
#[allow(clippy::unnecessary_cast)]
|
||||||
fn on_call<QT, S>(
|
fn on_call<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
_hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
call_len: usize,
|
call_len: usize,
|
||||||
@ -574,7 +576,7 @@ impl CallTraceCollector for FullBacktraceCollector {
|
|||||||
#[allow(clippy::unnecessary_cast)]
|
#[allow(clippy::unnecessary_cast)]
|
||||||
fn on_ret<QT, S>(
|
fn on_ret<QT, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
_hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
_pc: GuestAddr,
|
_pc: GuestAddr,
|
||||||
ret_addr: GuestAddr,
|
ret_addr: GuestAddr,
|
||||||
|
@ -20,7 +20,7 @@ use crate::{
|
|||||||
helper::{
|
helper::{
|
||||||
hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter,
|
hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter,
|
||||||
},
|
},
|
||||||
hooks::QemuHooks,
|
hooks::{Hook, QemuHooks},
|
||||||
GuestAddr,
|
GuestAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -83,16 +83,16 @@ impl<S> QemuHelper<S> for QemuCmpLogHelper
|
|||||||
where
|
where
|
||||||
S: UsesInput + HasMetadata,
|
S: UsesInput + HasMetadata,
|
||||||
{
|
{
|
||||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
hooks.cmps_raw(
|
hooks.cmps(
|
||||||
Some(gen_unique_cmp_ids::<QT, S>),
|
Hook::Function(gen_unique_cmp_ids::<QT, S>),
|
||||||
Some(trace_cmp1_cmplog),
|
Hook::Raw(trace_cmp1_cmplog),
|
||||||
Some(trace_cmp2_cmplog),
|
Hook::Raw(trace_cmp2_cmplog),
|
||||||
Some(trace_cmp4_cmplog),
|
Hook::Raw(trace_cmp4_cmplog),
|
||||||
Some(trace_cmp8_cmplog),
|
Hook::Raw(trace_cmp8_cmplog),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,22 +127,22 @@ where
|
|||||||
{
|
{
|
||||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||||
|
|
||||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
hooks.cmps_raw(
|
hooks.cmps(
|
||||||
Some(gen_hashed_cmp_ids::<QT, S>),
|
Hook::Function(gen_hashed_cmp_ids::<QT, S>),
|
||||||
Some(trace_cmp1_cmplog),
|
Hook::Raw(trace_cmp1_cmplog),
|
||||||
Some(trace_cmp2_cmplog),
|
Hook::Raw(trace_cmp2_cmplog),
|
||||||
Some(trace_cmp4_cmplog),
|
Hook::Raw(trace_cmp4_cmplog),
|
||||||
Some(trace_cmp8_cmplog),
|
Hook::Raw(trace_cmp8_cmplog),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_unique_cmp_ids<QT, S>(
|
pub fn gen_unique_cmp_ids<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
state: Option<&mut S>,
|
state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
_size: usize,
|
_size: usize,
|
||||||
@ -174,7 +174,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_hashed_cmp_ids<QT, S>(
|
pub fn gen_hashed_cmp_ids<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
_size: usize,
|
_size: usize,
|
||||||
@ -192,25 +192,25 @@ where
|
|||||||
Some(hash_me(pc.into()) & (CMPLOG_MAP_W as u64 - 1))
|
Some(hash_me(pc.into()) & (CMPLOG_MAP_W as u64 - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn trace_cmp1_cmplog(id: u64, v0: u8, v1: u8, _data: u64) {
|
pub extern "C" fn trace_cmp1_cmplog(_: *const (), id: u64, v0: u8, v1: u8) {
|
||||||
unsafe {
|
unsafe {
|
||||||
__libafl_targets_cmplog_instructions(id as usize, 1, u64::from(v0), u64::from(v1));
|
__libafl_targets_cmplog_instructions(id as usize, 1, u64::from(v0), u64::from(v1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn trace_cmp2_cmplog(id: u64, v0: u16, v1: u16, _data: u64) {
|
pub extern "C" fn trace_cmp2_cmplog(_: *const (), id: u64, v0: u16, v1: u16) {
|
||||||
unsafe {
|
unsafe {
|
||||||
__libafl_targets_cmplog_instructions(id as usize, 2, u64::from(v0), u64::from(v1));
|
__libafl_targets_cmplog_instructions(id as usize, 2, u64::from(v0), u64::from(v1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn trace_cmp4_cmplog(id: u64, v0: u32, v1: u32, _data: u64) {
|
pub extern "C" fn trace_cmp4_cmplog(_: *const (), id: u64, v0: u32, v1: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
__libafl_targets_cmplog_instructions(id as usize, 4, u64::from(v0), u64::from(v1));
|
__libafl_targets_cmplog_instructions(id as usize, 4, u64::from(v0), u64::from(v1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn trace_cmp8_cmplog(id: u64, v0: u64, v1: u64, _data: u64) {
|
pub extern "C" fn trace_cmp8_cmplog(_: *const (), id: u64, v0: u64, v1: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
__libafl_targets_cmplog_instructions(id as usize, 8, v0, v1);
|
__libafl_targets_cmplog_instructions(id as usize, 8, v0, v1);
|
||||||
}
|
}
|
||||||
@ -238,7 +238,7 @@ impl QemuCmpLogRoutinesHelper {
|
|||||||
self.filter.allowed(addr)
|
self.filter.allowed(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn on_call(_pc: GuestAddr, k: u64) {
|
extern "C" fn on_call(k: u64, _pc: GuestAddr) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if CMPLOG_ENABLED == 0 {
|
if CMPLOG_ENABLED == 0 {
|
||||||
return;
|
return;
|
||||||
@ -266,7 +266,7 @@ impl QemuCmpLogRoutinesHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn gen_blocks_calls<QT, S>(
|
fn gen_blocks_calls<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
) -> Option<u64>
|
) -> Option<u64>
|
||||||
@ -317,7 +317,7 @@ impl QemuCmpLogRoutinesHelper {
|
|||||||
match u32::from(detail.0) {
|
match u32::from(detail.0) {
|
||||||
capstone::InsnGroupType::CS_GRP_CALL => {
|
capstone::InsnGroupType::CS_GRP_CALL => {
|
||||||
let k = (hash_me(pc.into())) & (CMPLOG_MAP_W as u64 - 1);
|
let k = (hash_me(pc.into())) & (CMPLOG_MAP_W as u64 - 1);
|
||||||
emu.set_hook(insn.address() as GuestAddr, Self::on_call, k, false);
|
emu.set_hook(k, insn.address() as GuestAddr, Self::on_call, false);
|
||||||
}
|
}
|
||||||
capstone::InsnGroupType::CS_GRP_RET
|
capstone::InsnGroupType::CS_GRP_RET
|
||||||
| capstone::InsnGroupType::CS_GRP_INVALID
|
| capstone::InsnGroupType::CS_GRP_INVALID
|
||||||
@ -363,10 +363,14 @@ impl<S> QemuHelper<S> for QemuCmpLogRoutinesHelper
|
|||||||
where
|
where
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
{
|
{
|
||||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
hooks.blocks(Some(Self::gen_blocks_calls::<QT, S>), None, None);
|
hooks.blocks(
|
||||||
|
Hook::Function(Self::gen_blocks_calls::<QT, S>),
|
||||||
|
Hook::Empty,
|
||||||
|
Hook::Empty,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::{
|
use crate::{
|
||||||
emu::{GuestAddr, GuestUsize},
|
emu::{GuestAddr, GuestUsize},
|
||||||
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||||
hooks::QemuHooks,
|
hooks::{Hook, QemuHooks},
|
||||||
Emulator,
|
Emulator,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -89,14 +89,14 @@ impl<S> QemuHelper<S> for QemuDrCovHelper
|
|||||||
where
|
where
|
||||||
S: UsesInput + HasMetadata,
|
S: UsesInput + HasMetadata,
|
||||||
{
|
{
|
||||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn init_hooks<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
hooks.blocks(
|
hooks.blocks(
|
||||||
Some(gen_unique_block_ids::<QT, S>),
|
Hook::Function(gen_unique_block_ids::<QT, S>),
|
||||||
Some(gen_block_lengths::<QT, S>),
|
Hook::Function(gen_block_lengths::<QT, S>),
|
||||||
Some(exec_trace_block::<QT, S>),
|
Hook::Function(exec_trace_block::<QT, S>),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_unique_block_ids<QT, S>(
|
pub fn gen_unique_block_ids<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
state: Option<&mut S>,
|
state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
) -> Option<u64>
|
) -> Option<u64>
|
||||||
@ -247,7 +247,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_block_lengths<QT, S>(
|
pub fn gen_block_lengths<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
block_length: GuestUsize,
|
block_length: GuestUsize,
|
||||||
@ -271,7 +271,7 @@ pub fn gen_block_lengths<QT, S>(
|
|||||||
.insert(pc, block_length);
|
.insert(pc, block_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exec_trace_block<QT, S>(hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, id: u64)
|
pub fn exec_trace_block<QT, S>(hooks: &mut QemuHooks<QT, S>, _state: Option<&mut S>, id: u64)
|
||||||
where
|
where
|
||||||
S: HasMetadata,
|
S: HasMetadata,
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
|
@ -13,7 +13,7 @@ use crate::{
|
|||||||
helper::{
|
helper::{
|
||||||
hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter,
|
hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter,
|
||||||
},
|
},
|
||||||
hooks::QemuHooks,
|
hooks::{Hook, QemuHooks},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
@ -87,17 +87,20 @@ impl<S> QemuHelper<S> for QemuEdgeCoverageHelper
|
|||||||
where
|
where
|
||||||
S: UsesInput + HasMetadata,
|
S: UsesInput + HasMetadata,
|
||||||
{
|
{
|
||||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
if self.use_hitcounts {
|
if self.use_hitcounts {
|
||||||
hooks.edges_raw(
|
hooks.edges(
|
||||||
Some(gen_unique_edge_ids::<QT, S>),
|
Hook::Function(gen_unique_edge_ids::<QT, S>),
|
||||||
Some(trace_edge_hitcount),
|
Hook::Raw(trace_edge_hitcount),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
hooks.edges_raw(Some(gen_unique_edge_ids::<QT, S>), Some(trace_edge_single));
|
hooks.edges(
|
||||||
|
Hook::Function(gen_unique_edge_ids::<QT, S>),
|
||||||
|
Hook::Raw(trace_edge_single),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,19 +159,19 @@ where
|
|||||||
{
|
{
|
||||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||||
|
|
||||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
if self.use_hitcounts {
|
if self.use_hitcounts {
|
||||||
hooks.edges_raw(
|
hooks.edges(
|
||||||
Some(gen_hashed_edge_ids::<QT, S>),
|
Hook::Function(gen_hashed_edge_ids::<QT, S>),
|
||||||
Some(trace_edge_hitcount_ptr),
|
Hook::Raw(trace_edge_hitcount_ptr),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
hooks.edges_raw(
|
hooks.edges(
|
||||||
Some(gen_hashed_edge_ids::<QT, S>),
|
Hook::Function(gen_hashed_edge_ids::<QT, S>),
|
||||||
Some(trace_edge_single_ptr),
|
Hook::Raw(trace_edge_single_ptr),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,21 +229,21 @@ where
|
|||||||
{
|
{
|
||||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||||
|
|
||||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
if self.use_hitcounts {
|
if self.use_hitcounts {
|
||||||
hooks.blocks_raw(
|
hooks.blocks(
|
||||||
Some(gen_hashed_block_ids::<QT, S>),
|
Hook::Function(gen_hashed_block_ids::<QT, S>),
|
||||||
None,
|
Hook::Empty,
|
||||||
Some(trace_block_transition_hitcount),
|
Hook::Raw(trace_block_transition_hitcount),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
hooks.blocks_raw(
|
hooks.blocks(
|
||||||
Some(gen_hashed_block_ids::<QT, S>),
|
Hook::Function(gen_hashed_block_ids::<QT, S>),
|
||||||
None,
|
Hook::Empty,
|
||||||
Some(trace_block_transition_single),
|
Hook::Raw(trace_block_transition_single),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,7 +252,7 @@ where
|
|||||||
thread_local!(static PREV_LOC : UnsafeCell<u64> = UnsafeCell::new(0));
|
thread_local!(static PREV_LOC : UnsafeCell<u64> = UnsafeCell::new(0));
|
||||||
|
|
||||||
pub fn gen_unique_edge_ids<QT, S>(
|
pub fn gen_unique_edge_ids<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
state: Option<&mut S>,
|
state: Option<&mut S>,
|
||||||
src: GuestAddr,
|
src: GuestAddr,
|
||||||
dest: GuestAddr,
|
dest: GuestAddr,
|
||||||
@ -296,20 +299,20 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn trace_edge_hitcount(id: u64, _data: u64) {
|
pub extern "C" fn trace_edge_hitcount(_: *const (), id: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
EDGES_MAP[id as usize] = EDGES_MAP[id as usize].wrapping_add(1);
|
EDGES_MAP[id as usize] = EDGES_MAP[id as usize].wrapping_add(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn trace_edge_single(id: u64, _data: u64) {
|
pub extern "C" fn trace_edge_single(_: *const (), id: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
EDGES_MAP[id as usize] = 1;
|
EDGES_MAP[id as usize] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_hashed_edge_ids<QT, S>(
|
pub fn gen_hashed_edge_ids<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
src: GuestAddr,
|
src: GuestAddr,
|
||||||
dest: GuestAddr,
|
dest: GuestAddr,
|
||||||
@ -331,14 +334,14 @@ where
|
|||||||
Some((hash_me(src as u64) ^ hash_me(dest as u64)) & (unsafe { EDGES_MAP_PTR_NUM } as u64 - 1))
|
Some((hash_me(src as u64) ^ hash_me(dest as u64)) & (unsafe { EDGES_MAP_PTR_NUM } as u64 - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn trace_edge_hitcount_ptr(id: u64, _data: u64) {
|
pub extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = EDGES_MAP_PTR.add(id as usize);
|
let ptr = EDGES_MAP_PTR.add(id as usize);
|
||||||
*ptr = (*ptr).wrapping_add(1);
|
*ptr = (*ptr).wrapping_add(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn trace_edge_single_ptr(id: u64, _data: u64) {
|
pub extern "C" fn trace_edge_single_ptr(_: *const (), id: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = EDGES_MAP_PTR.add(id as usize);
|
let ptr = EDGES_MAP_PTR.add(id as usize);
|
||||||
*ptr = 1;
|
*ptr = 1;
|
||||||
@ -347,7 +350,7 @@ pub extern "C" fn trace_edge_single_ptr(id: u64, _data: u64) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
pub fn gen_addr_block_ids<QT, S>(
|
pub fn gen_addr_block_ids<QT, S>(
|
||||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
_hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
) -> Option<u64>
|
) -> Option<u64>
|
||||||
@ -362,7 +365,7 @@ where
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pub fn gen_hashed_block_ids<QT, S>(
|
pub fn gen_hashed_block_ids<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
) -> Option<u64>
|
) -> Option<u64>
|
||||||
@ -383,7 +386,7 @@ where
|
|||||||
Some(hash_me(pc as u64))
|
Some(hash_me(pc as u64))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn trace_block_transition_hitcount(id: u64, _data: u64) {
|
pub extern "C" fn trace_block_transition_hitcount(_: *const (), id: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
PREV_LOC.with(|prev_loc| {
|
PREV_LOC.with(|prev_loc| {
|
||||||
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_NUM - 1);
|
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_NUM - 1);
|
||||||
@ -394,7 +397,7 @@ pub extern "C" fn trace_block_transition_hitcount(id: u64, _data: u64) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn trace_block_transition_single(id: u64, _data: u64) {
|
pub extern "C" fn trace_block_transition_single(_: *const (), id: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
PREV_LOC.with(|prev_loc| {
|
PREV_LOC.with(|prev_loc| {
|
||||||
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_NUM - 1);
|
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_NUM - 1);
|
||||||
|
@ -14,11 +14,7 @@ use std::{
|
|||||||
ffi::{CStr, CString},
|
ffi::{CStr, CString},
|
||||||
ptr::null_mut,
|
ptr::null_mut,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{slice::from_raw_parts, str::from_utf8_unchecked};
|
||||||
slice::from_raw_parts,
|
|
||||||
str::from_utf8_unchecked,
|
|
||||||
sync::{Mutex, OnceLock},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
@ -224,11 +220,12 @@ pub enum VerifyAccess {
|
|||||||
Write = libc::PROT_READ | libc::PROT_WRITE,
|
Write = libc::PROT_READ | libc::PROT_WRITE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// syshook_ret
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[cfg_attr(feature = "python", pyclass)]
|
#[cfg_attr(feature = "python", pyclass)]
|
||||||
#[cfg_attr(feature = "python", derive(FromPyObject))]
|
#[cfg_attr(feature = "python", derive(FromPyObject))]
|
||||||
pub struct SyscallHookResult {
|
pub struct SyscallHookResult {
|
||||||
pub retval: u64,
|
pub retval: GuestAddr,
|
||||||
pub skip_syscall: bool,
|
pub skip_syscall: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +234,7 @@ pub struct SyscallHookResult {
|
|||||||
impl SyscallHookResult {
|
impl SyscallHookResult {
|
||||||
#[new]
|
#[new]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(value: Option<u64>) -> Self {
|
pub fn new(value: Option<GuestAddr>) -> Self {
|
||||||
value.map_or(
|
value.map_or(
|
||||||
Self {
|
Self {
|
||||||
retval: 0,
|
retval: 0,
|
||||||
@ -254,7 +251,7 @@ impl SyscallHookResult {
|
|||||||
#[cfg(not(feature = "python"))]
|
#[cfg(not(feature = "python"))]
|
||||||
impl SyscallHookResult {
|
impl SyscallHookResult {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(value: Option<u64>) -> Self {
|
pub fn new(value: Option<GuestAddr>) -> Self {
|
||||||
value.map_or(
|
value.map_or(
|
||||||
Self {
|
Self {
|
||||||
retval: 0,
|
retval: 0,
|
||||||
@ -340,13 +337,6 @@ extern "C" {
|
|||||||
static guest_base: usize;
|
static guest_base: usize;
|
||||||
static mut mmap_next_start: GuestAddr;
|
static mut mmap_next_start: GuestAddr;
|
||||||
|
|
||||||
static mut libafl_on_thread_hook: unsafe extern "C" fn(u32);
|
|
||||||
|
|
||||||
static mut libafl_pre_syscall_hook:
|
|
||||||
unsafe extern "C" fn(i32, u64, u64, u64, u64, u64, u64, u64, u64) -> SyscallHookResult;
|
|
||||||
static mut libafl_post_syscall_hook:
|
|
||||||
unsafe extern "C" fn(u64, i32, u64, u64, u64, u64, u64, u64, u64, u64) -> u64;
|
|
||||||
|
|
||||||
static mut libafl_dump_core_hook: unsafe extern "C" fn(i32);
|
static mut libafl_dump_core_hook: unsafe extern "C" fn(i32);
|
||||||
static mut libafl_force_dfl: i32;
|
static mut libafl_force_dfl: i32;
|
||||||
}
|
}
|
||||||
@ -370,6 +360,7 @@ extern "C" fn qemu_cleanup_atexit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO rely completely on libafl_qemu_sys
|
||||||
extern "C" {
|
extern "C" {
|
||||||
//static libafl_page_size: GuestUsize;
|
//static libafl_page_size: GuestUsize;
|
||||||
fn libafl_page_from_addr(addr: GuestAddr) -> GuestAddr;
|
fn libafl_page_from_addr(addr: GuestAddr) -> GuestAddr;
|
||||||
@ -395,87 +386,10 @@ extern "C" {
|
|||||||
fn libafl_flush_jit();
|
fn libafl_flush_jit();
|
||||||
fn libafl_qemu_trigger_breakpoint(cpu: CPUStatePtr);
|
fn libafl_qemu_trigger_breakpoint(cpu: CPUStatePtr);
|
||||||
|
|
||||||
fn libafl_qemu_set_hook(
|
|
||||||
addr: GuestAddr,
|
|
||||||
callback: extern "C" fn(GuestAddr, u64),
|
|
||||||
data: u64,
|
|
||||||
invalidate_block: i32,
|
|
||||||
) -> usize;
|
|
||||||
// fn libafl_qemu_remove_hook(num: usize, invalidate_block: i32) -> i32;
|
|
||||||
fn libafl_qemu_remove_hooks_at(addr: GuestAddr, invalidate_block: i32) -> usize;
|
|
||||||
|
|
||||||
fn strlen(s: *const u8) -> usize;
|
fn strlen(s: *const u8) -> usize;
|
||||||
|
|
||||||
// void libafl_add_edge_hook(uint64_t (*gen)(target_ulong src, target_ulong dst), void (*exec)(uint64_t id));
|
|
||||||
fn libafl_add_edge_hook(
|
|
||||||
gen: Option<extern "C" fn(GuestAddr, GuestAddr, u64) -> u64>,
|
|
||||||
exec: Option<extern "C" fn(u64, u64)>,
|
|
||||||
data: u64,
|
|
||||||
);
|
|
||||||
|
|
||||||
// void libafl_add_block_hook(uint64_t (*gen)(target_ulong pc), void (*exec)(uint64_t id));
|
|
||||||
fn libafl_add_block_hook(
|
|
||||||
gen: Option<extern "C" fn(GuestAddr, u64) -> u64>,
|
|
||||||
post_gen: Option<extern "C" fn(GuestAddr, GuestUsize, u64)>,
|
|
||||||
exec: Option<extern "C" fn(u64, u64)>,
|
|
||||||
data: u64,
|
|
||||||
);
|
|
||||||
|
|
||||||
// void libafl_add_read_hook(uint64_t (*gen)(target_ulong pc, size_t size, uint64_t data),
|
|
||||||
// void (*exec1)(uint64_t id, target_ulong addr, uint64_t data),
|
|
||||||
// void (*exec2)(uint64_t id, target_ulong addr, uint64_t data),
|
|
||||||
// void (*exec4)(uint64_t id, target_ulong addr, uint64_t data),
|
|
||||||
// void (*exec8)(uint64_t id, target_ulong addr, uint64_t data),
|
|
||||||
// void (*exec_n)(uint64_t id, target_ulong addr, size_t size, uint64_t data),
|
|
||||||
// uint64_t data);
|
|
||||||
fn libafl_add_read_hook(
|
|
||||||
gen: Option<extern "C" fn(GuestAddr, MemAccessInfo, u64) -> u64>,
|
|
||||||
exec1: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
|
||||||
exec2: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
|
||||||
exec4: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
|
||||||
exec8: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
|
||||||
exec_n: Option<extern "C" fn(u64, GuestAddr, usize, u64)>,
|
|
||||||
data: u64,
|
|
||||||
);
|
|
||||||
|
|
||||||
// void libafl_add_write_hook(uint64_t (*gen)(target_ulong pc, size_t size, uint64_t data),
|
|
||||||
// void (*exec1)(uint64_t id, target_ulong addr, uint64_t data),
|
|
||||||
// void (*exec2)(uint64_t id, target_ulong addr, uint64_t data),
|
|
||||||
// void (*exec4)(uint64_t id, target_ulong addr, uint64_t data),
|
|
||||||
// void (*exec8)(uint64_t id, target_ulong addr, uint64_t data),
|
|
||||||
// void (*exec_n)(uint64_t id, target_ulong addr, size_t size, uint64_t data),
|
|
||||||
// uint64_t data);
|
|
||||||
fn libafl_add_write_hook(
|
|
||||||
gen: Option<extern "C" fn(GuestAddr, MemAccessInfo, u64) -> u64>,
|
|
||||||
exec1: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
|
||||||
exec2: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
|
||||||
exec4: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
|
||||||
exec8: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
|
||||||
exec_n: Option<extern "C" fn(u64, GuestAddr, usize, u64)>,
|
|
||||||
data: u64,
|
|
||||||
);
|
|
||||||
|
|
||||||
// void libafl_add_cmp_hook(uint64_t (*gen)(target_ulong pc, size_t size, uint64_t data),
|
|
||||||
// void (*exec1)(uint64_t id, uint8_t v0, uint8_t v1, uint64_t data),
|
|
||||||
// void (*exec2)(uint64_t id, uint16_t v0, uint16_t v1, uint64_t data),
|
|
||||||
// void (*exec4)(uint64_t id, uint32_t v0, uint32_t v1, uint64_t data),
|
|
||||||
// void (*exec8)(uint64_t id, uint64_t v0, uint64_t v1, uint64_t data),
|
|
||||||
// uint64_t data);
|
|
||||||
fn libafl_add_cmp_hook(
|
|
||||||
gen: Option<extern "C" fn(GuestAddr, usize, u64) -> u64>,
|
|
||||||
exec1: Option<extern "C" fn(u64, u8, u8, u64)>,
|
|
||||||
exec2: Option<extern "C" fn(u64, u16, u16, u64)>,
|
|
||||||
exec4: Option<extern "C" fn(u64, u32, u32, u64)>,
|
|
||||||
exec8: Option<extern "C" fn(u64, u64, u64, u64)>,
|
|
||||||
data: u64,
|
|
||||||
);
|
|
||||||
|
|
||||||
// void libafl_add_backdoor_hook(void (*exec)(uint64_t id, uint64_t data),
|
|
||||||
// uint64_t data)
|
|
||||||
fn libafl_add_backdoor_hook(exec: extern "C" fn(GuestAddr, u64), data: u64);
|
|
||||||
|
|
||||||
fn libafl_qemu_add_gdb_cmd(
|
fn libafl_qemu_add_gdb_cmd(
|
||||||
callback: extern "C" fn(*const u8, usize, *const ()) -> i32,
|
callback: extern "C" fn(*const (), *const u8, usize) -> i32,
|
||||||
data: *const (),
|
data: *const (),
|
||||||
);
|
);
|
||||||
fn libafl_qemu_gdb_reply(buf: *const u8, len: usize);
|
fn libafl_qemu_gdb_reply(buf: *const u8, len: usize);
|
||||||
@ -550,7 +464,7 @@ pub(crate) struct FatPtr(pub *const c_void, pub *const c_void);
|
|||||||
|
|
||||||
static mut GDB_COMMANDS: Vec<FatPtr> = vec![];
|
static mut GDB_COMMANDS: Vec<FatPtr> = vec![];
|
||||||
|
|
||||||
extern "C" fn gdb_cmd(buf: *const u8, len: usize, data: *const ()) -> i32 {
|
extern "C" fn gdb_cmd(data: *const (), buf: *const u8, len: usize) -> i32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
let closure = &mut *(data as *mut Box<dyn for<'r> FnMut(&Emulator, &'r str) -> bool>);
|
let closure = &mut *(data as *mut Box<dyn for<'r> FnMut(&Emulator, &'r str) -> bool>);
|
||||||
let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len));
|
let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len));
|
||||||
@ -845,11 +759,72 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static EMULATOR_IS_INITIALIZED: OnceLock<Mutex<bool>> = OnceLock::new();
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
pub struct HookId(pub(crate) usize);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
use std::pin::Pin;
|
||||||
pub struct Emulator {
|
|
||||||
_private: (),
|
#[derive(Debug)]
|
||||||
|
pub struct HookData(u64);
|
||||||
|
|
||||||
|
impl<T> From<Pin<&mut T>> for HookData {
|
||||||
|
fn from(value: Pin<&mut T>) -> Self {
|
||||||
|
unsafe { HookData(core::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Pin<&T>> for HookData {
|
||||||
|
fn from(value: Pin<&T>) -> Self {
|
||||||
|
unsafe { HookData(core::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<&'static mut T> for HookData {
|
||||||
|
fn from(value: &'static mut T) -> Self {
|
||||||
|
unsafe { HookData(core::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<&'static T> for HookData {
|
||||||
|
fn from(value: &'static T) -> Self {
|
||||||
|
unsafe { HookData(core::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<*mut T> for HookData {
|
||||||
|
fn from(value: *mut T) -> Self {
|
||||||
|
unsafe { HookData(core::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<*const T> for HookData {
|
||||||
|
fn from(value: *const T) -> Self {
|
||||||
|
unsafe { HookData(core::mem::transmute(value)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u64> for HookData {
|
||||||
|
fn from(value: u64) -> Self {
|
||||||
|
HookData(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for HookData {
|
||||||
|
fn from(value: u32) -> Self {
|
||||||
|
HookData(value as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u16> for HookData {
|
||||||
|
fn from(value: u16) -> Self {
|
||||||
|
HookData(value as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for HookData {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
HookData(value as u64)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -940,19 +915,17 @@ impl From<EmuError> for libafl::Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static mut EMULATOR_IS_INITIALIZED: bool = false;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Emulator {
|
||||||
|
_private: (),
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::unused_self)]
|
#[allow(clippy::unused_self)]
|
||||||
impl Emulator {
|
impl Emulator {
|
||||||
#[allow(clippy::must_use_candidate, clippy::similar_names)]
|
#[allow(clippy::must_use_candidate, clippy::similar_names)]
|
||||||
pub fn new(args: &[String], env: &[(String, String)]) -> Result<Emulator, EmuError> {
|
pub fn new(args: &[String], env: &[(String, String)]) -> Result<Emulator, EmuError> {
|
||||||
let mut is_initialized = EMULATOR_IS_INITIALIZED
|
|
||||||
.get_or_init(|| Mutex::new(false))
|
|
||||||
.lock()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if *is_initialized {
|
|
||||||
return Err(EmuError::MultipleInstances);
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return Err(EmuError::EmptyArgs);
|
return Err(EmuError::EmptyArgs);
|
||||||
}
|
}
|
||||||
@ -961,6 +934,14 @@ impl Emulator {
|
|||||||
if i32::try_from(argc).is_err() {
|
if i32::try_from(argc).is_err() {
|
||||||
return Err(EmuError::TooManyArgs(argc));
|
return Err(EmuError::TooManyArgs(argc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if EMULATOR_IS_INITIALIZED {
|
||||||
|
return Err(EmuError::MultipleInstances);
|
||||||
|
}
|
||||||
|
EMULATOR_IS_INITIALIZED = true;
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_possible_wrap)]
|
#[allow(clippy::cast_possible_wrap)]
|
||||||
let argc = argc as i32;
|
let argc = argc as i32;
|
||||||
|
|
||||||
@ -985,11 +966,21 @@ impl Emulator {
|
|||||||
libc::atexit(qemu_cleanup_atexit);
|
libc::atexit(qemu_cleanup_atexit);
|
||||||
libafl_qemu_sys::syx_snapshot_init();
|
libafl_qemu_sys::syx_snapshot_init();
|
||||||
}
|
}
|
||||||
*is_initialized = true;
|
|
||||||
}
|
}
|
||||||
Ok(Emulator { _private: () })
|
Ok(Emulator { _private: () })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn get() -> Option<Self> {
|
||||||
|
unsafe {
|
||||||
|
if EMULATOR_IS_INITIALIZED {
|
||||||
|
Some(Self::new_empty())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn new_empty() -> Emulator {
|
pub(crate) fn new_empty() -> Emulator {
|
||||||
Emulator { _private: () }
|
Emulator { _private: () }
|
||||||
@ -1141,22 +1132,6 @@ impl Emulator {
|
|||||||
libafl_force_dfl = 1;
|
libafl_force_dfl = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_hook(
|
|
||||||
&self,
|
|
||||||
addr: GuestAddr,
|
|
||||||
callback: extern "C" fn(GuestAddr, u64),
|
|
||||||
data: u64,
|
|
||||||
invalidate_block: bool,
|
|
||||||
) -> usize {
|
|
||||||
unsafe { libafl_qemu_set_hook(addr.into(), callback, data, i32::from(invalidate_block)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn remove_hook(&self, addr: GuestAddr, invalidate_block: bool) -> usize {
|
|
||||||
unsafe { libafl_qemu_remove_hooks_at(addr.into(), i32::from(invalidate_block)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function will run the emulator until the next breakpoint, or until finish.
|
/// This function will run the emulator until the next breakpoint, or until finish.
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
@ -1282,72 +1257,250 @@ impl Emulator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_edge_hooks(
|
// TODO set T lifetime to be like Emulator
|
||||||
|
pub fn set_hook<T: Into<HookData>>(
|
||||||
&self,
|
&self,
|
||||||
gen: Option<extern "C" fn(GuestAddr, GuestAddr, u64) -> u64>,
|
data: T,
|
||||||
exec: Option<extern "C" fn(u64, u64)>,
|
addr: GuestAddr,
|
||||||
data: u64,
|
callback: extern "C" fn(T, GuestAddr),
|
||||||
) {
|
invalidate_block: bool,
|
||||||
unsafe { libafl_add_edge_hook(gen, exec, data) }
|
) -> HookId {
|
||||||
|
unsafe {
|
||||||
|
let data: u64 = data.into().0;
|
||||||
|
let callback: extern "C" fn(u64, GuestAddr) = core::mem::transmute(callback);
|
||||||
|
let num = libafl_qemu_sys::libafl_qemu_set_hook(
|
||||||
|
addr.into(),
|
||||||
|
Some(callback),
|
||||||
|
data,
|
||||||
|
i32::from(invalidate_block),
|
||||||
|
);
|
||||||
|
HookId(num)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_block_hooks(
|
#[must_use]
|
||||||
&self,
|
pub fn remove_hook(&self, id: HookId, invalidate_block: bool) -> bool {
|
||||||
gen: Option<extern "C" fn(GuestAddr, u64) -> u64>,
|
unsafe { libafl_qemu_sys::libafl_qemu_remove_hook(id.0, i32::from(invalidate_block)) != 0 }
|
||||||
post_gen: Option<extern "C" fn(GuestAddr, GuestUsize, u64)>,
|
|
||||||
exec: Option<extern "C" fn(u64, u64)>,
|
|
||||||
data: u64,
|
|
||||||
) {
|
|
||||||
unsafe { libafl_add_block_hook(gen, post_gen, exec, data) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_read_hooks(
|
#[must_use]
|
||||||
|
pub fn remove_hooks_at(&self, addr: GuestAddr, invalidate_block: bool) -> usize {
|
||||||
|
unsafe {
|
||||||
|
libafl_qemu_sys::libafl_qemu_remove_hooks_at(addr.into(), i32::from(invalidate_block))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_edge_hooks<T: Into<HookData>>(
|
||||||
&self,
|
&self,
|
||||||
gen: Option<extern "C" fn(GuestAddr, MemAccessInfo, u64) -> u64>,
|
data: T,
|
||||||
exec1: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
gen: Option<extern "C" fn(T, GuestAddr, GuestAddr) -> u64>,
|
||||||
exec2: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
exec: Option<extern "C" fn(T, u64)>,
|
||||||
exec4: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
) -> HookId {
|
||||||
exec8: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
unsafe {
|
||||||
exec_n: Option<extern "C" fn(u64, GuestAddr, usize, u64)>,
|
let data: u64 = data.into().0;
|
||||||
data: u64,
|
let gen: Option<extern "C" fn(u64, GuestAddr, GuestAddr) -> u64> =
|
||||||
) {
|
core::mem::transmute(gen);
|
||||||
unsafe { libafl_add_read_hook(gen, exec1, exec2, exec4, exec8, exec_n, data) }
|
let exec: Option<extern "C" fn(u64, u64)> = core::mem::transmute(exec);
|
||||||
|
let num = libafl_qemu_sys::libafl_add_edge_hook(gen, exec, data);
|
||||||
|
HookId(num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_block_hooks<T: Into<HookData>>(
|
||||||
|
&self,
|
||||||
|
data: T,
|
||||||
|
gen: Option<extern "C" fn(T, GuestAddr) -> u64>,
|
||||||
|
post_gen: Option<extern "C" fn(T, GuestAddr, GuestUsize)>,
|
||||||
|
exec: Option<extern "C" fn(T, u64)>,
|
||||||
|
) -> HookId {
|
||||||
|
unsafe {
|
||||||
|
let data: u64 = data.into().0;
|
||||||
|
let gen: Option<extern "C" fn(u64, GuestAddr) -> u64> = core::mem::transmute(gen);
|
||||||
|
let post_gen: Option<extern "C" fn(u64, GuestAddr, GuestUsize)> =
|
||||||
|
core::mem::transmute(post_gen);
|
||||||
|
let exec: Option<extern "C" fn(u64, u64)> = core::mem::transmute(exec);
|
||||||
|
let num = libafl_qemu_sys::libafl_add_block_hook(gen, post_gen, exec, data);
|
||||||
|
HookId(num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_read_hooks<T: Into<HookData>>(
|
||||||
|
&self,
|
||||||
|
data: T,
|
||||||
|
gen: Option<extern "C" fn(T, GuestAddr, MemAccessInfo) -> u64>,
|
||||||
|
exec1: Option<extern "C" fn(T, u64, GuestAddr)>,
|
||||||
|
exec2: Option<extern "C" fn(T, u64, GuestAddr)>,
|
||||||
|
exec4: Option<extern "C" fn(T, u64, GuestAddr)>,
|
||||||
|
exec8: Option<extern "C" fn(T, u64, GuestAddr)>,
|
||||||
|
exec_n: Option<extern "C" fn(T, u64, GuestAddr, usize)>,
|
||||||
|
) -> HookId {
|
||||||
|
unsafe {
|
||||||
|
let data: u64 = data.into().0;
|
||||||
|
let gen: Option<extern "C" fn(u64, GuestAddr, libafl_qemu_sys::MemOpIdx) -> u64> =
|
||||||
|
core::mem::transmute(gen);
|
||||||
|
let exec1: Option<extern "C" fn(u64, u64, GuestAddr)> = core::mem::transmute(exec1);
|
||||||
|
let exec2: Option<extern "C" fn(u64, u64, GuestAddr)> = core::mem::transmute(exec2);
|
||||||
|
let exec4: Option<extern "C" fn(u64, u64, GuestAddr)> = core::mem::transmute(exec4);
|
||||||
|
let exec8: Option<extern "C" fn(u64, u64, GuestAddr)> = core::mem::transmute(exec8);
|
||||||
|
let exec_n: Option<extern "C" fn(u64, u64, GuestAddr, usize)> =
|
||||||
|
core::mem::transmute(exec_n);
|
||||||
|
let num = libafl_qemu_sys::libafl_add_read_hook(
|
||||||
|
gen, exec1, exec2, exec4, exec8, exec_n, data,
|
||||||
|
);
|
||||||
|
HookId(num)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO add MemOp info
|
// TODO add MemOp info
|
||||||
pub fn add_write_hooks(
|
pub fn add_write_hooks<T: Into<HookData>>(
|
||||||
&self,
|
&self,
|
||||||
gen: Option<extern "C" fn(GuestAddr, MemAccessInfo, u64) -> u64>,
|
data: T,
|
||||||
exec1: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
gen: Option<extern "C" fn(T, GuestAddr, MemAccessInfo) -> u64>,
|
||||||
exec2: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
exec1: Option<extern "C" fn(T, u64, GuestAddr)>,
|
||||||
exec4: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
exec2: Option<extern "C" fn(T, u64, GuestAddr)>,
|
||||||
exec8: Option<extern "C" fn(u64, GuestAddr, u64)>,
|
exec4: Option<extern "C" fn(T, u64, GuestAddr)>,
|
||||||
exec_n: Option<extern "C" fn(u64, GuestAddr, usize, u64)>,
|
exec8: Option<extern "C" fn(T, u64, GuestAddr)>,
|
||||||
data: u64,
|
exec_n: Option<extern "C" fn(T, u64, GuestAddr, usize)>,
|
||||||
) {
|
) -> HookId {
|
||||||
unsafe { libafl_add_write_hook(gen, exec1, exec2, exec4, exec8, exec_n, data) }
|
unsafe {
|
||||||
|
let data: u64 = data.into().0;
|
||||||
|
let gen: Option<extern "C" fn(u64, GuestAddr, libafl_qemu_sys::MemOpIdx) -> u64> =
|
||||||
|
core::mem::transmute(gen);
|
||||||
|
let exec1: Option<extern "C" fn(u64, u64, GuestAddr)> = core::mem::transmute(exec1);
|
||||||
|
let exec2: Option<extern "C" fn(u64, u64, GuestAddr)> = core::mem::transmute(exec2);
|
||||||
|
let exec4: Option<extern "C" fn(u64, u64, GuestAddr)> = core::mem::transmute(exec4);
|
||||||
|
let exec8: Option<extern "C" fn(u64, u64, GuestAddr)> = core::mem::transmute(exec8);
|
||||||
|
let exec_n: Option<extern "C" fn(u64, u64, GuestAddr, usize)> =
|
||||||
|
core::mem::transmute(exec_n);
|
||||||
|
let num = libafl_qemu_sys::libafl_add_write_hook(
|
||||||
|
gen, exec1, exec2, exec4, exec8, exec_n, data,
|
||||||
|
);
|
||||||
|
HookId(num)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_cmp_hooks(
|
pub fn add_cmp_hooks<T: Into<HookData>>(
|
||||||
&self,
|
&self,
|
||||||
gen: Option<extern "C" fn(GuestAddr, usize, u64) -> u64>,
|
data: T,
|
||||||
exec1: Option<extern "C" fn(u64, u8, u8, u64)>,
|
gen: Option<extern "C" fn(T, GuestAddr, usize) -> u64>,
|
||||||
exec2: Option<extern "C" fn(u64, u16, u16, u64)>,
|
exec1: Option<extern "C" fn(T, u64, u8, u8)>,
|
||||||
exec4: Option<extern "C" fn(u64, u32, u32, u64)>,
|
exec2: Option<extern "C" fn(T, u64, u16, u16)>,
|
||||||
exec8: Option<extern "C" fn(u64, u64, u64, u64)>,
|
exec4: Option<extern "C" fn(T, u64, u32, u32)>,
|
||||||
data: u64,
|
exec8: Option<extern "C" fn(T, u64, u64, u64)>,
|
||||||
) {
|
) -> HookId {
|
||||||
unsafe { libafl_add_cmp_hook(gen, exec1, exec2, exec4, exec8, data) }
|
unsafe {
|
||||||
|
let data: u64 = data.into().0;
|
||||||
|
let gen: Option<extern "C" fn(u64, GuestAddr, usize) -> u64> =
|
||||||
|
core::mem::transmute(gen);
|
||||||
|
let exec1: Option<extern "C" fn(u64, u64, u8, u8)> = core::mem::transmute(exec1);
|
||||||
|
let exec2: Option<extern "C" fn(u64, u64, u16, u16)> = core::mem::transmute(exec2);
|
||||||
|
let exec4: Option<extern "C" fn(u64, u64, u32, u32)> = core::mem::transmute(exec4);
|
||||||
|
let exec8: Option<extern "C" fn(u64, u64, u64, u64)> = core::mem::transmute(exec8);
|
||||||
|
let num = libafl_qemu_sys::libafl_add_cmp_hook(gen, exec1, exec2, exec4, exec8, data);
|
||||||
|
HookId(num)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_backdoor_hook(&self, exec: extern "C" fn(GuestAddr, u64), data: u64) {
|
pub fn add_backdoor_hook<T: Into<HookData>>(
|
||||||
unsafe { libafl_add_backdoor_hook(exec, data) };
|
&self,
|
||||||
|
data: T,
|
||||||
|
callback: extern "C" fn(T, GuestAddr),
|
||||||
|
) -> HookId {
|
||||||
|
unsafe {
|
||||||
|
let data: u64 = data.into().0;
|
||||||
|
let callback: extern "C" fn(u64, GuestAddr) = core::mem::transmute(callback);
|
||||||
|
let num = libafl_qemu_sys::libafl_add_backdoor_hook(Some(callback), data);
|
||||||
|
HookId(num)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
pub fn set_on_thread_hook(&self, hook: extern "C" fn(tid: u32)) {
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub fn add_pre_syscall_hook<T: Into<HookData>>(
|
||||||
|
&self,
|
||||||
|
data: T,
|
||||||
|
callback: extern "C" fn(
|
||||||
|
T,
|
||||||
|
i32,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
) -> SyscallHookResult,
|
||||||
|
) -> HookId {
|
||||||
unsafe {
|
unsafe {
|
||||||
libafl_on_thread_hook = hook;
|
let data: u64 = data.into().0;
|
||||||
|
let callback: extern "C" fn(
|
||||||
|
u64,
|
||||||
|
i32,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
) -> libafl_qemu_sys::syshook_ret = core::mem::transmute(callback);
|
||||||
|
let num = libafl_qemu_sys::libafl_add_pre_syscall_hook(Some(callback), data);
|
||||||
|
HookId(num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(emulation_mode = "usermode")]
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub fn add_post_syscall_hook<T: Into<HookData>>(
|
||||||
|
&self,
|
||||||
|
data: T,
|
||||||
|
callback: extern "C" fn(
|
||||||
|
T,
|
||||||
|
GuestAddr,
|
||||||
|
i32,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
) -> GuestAddr,
|
||||||
|
) -> HookId {
|
||||||
|
unsafe {
|
||||||
|
let data: u64 = data.into().0;
|
||||||
|
let callback: extern "C" fn(
|
||||||
|
u64,
|
||||||
|
GuestAddr,
|
||||||
|
i32,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
GuestAddr,
|
||||||
|
) -> GuestAddr = core::mem::transmute(callback);
|
||||||
|
let num = libafl_qemu_sys::libafl_add_post_syscall_hook(Some(callback), data);
|
||||||
|
HookId(num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(emulation_mode = "usermode")]
|
||||||
|
pub fn add_new_thread_hook<T: Into<HookData>>(
|
||||||
|
&self,
|
||||||
|
data: T,
|
||||||
|
callback: extern "C" fn(T, tid: u32) -> bool,
|
||||||
|
) -> HookId {
|
||||||
|
unsafe {
|
||||||
|
let data: u64 = data.into().0;
|
||||||
|
let callback: extern "C" fn(u64, u32) -> bool = core::mem::transmute(callback);
|
||||||
|
let num = libafl_qemu_sys::libafl_add_new_thread_hook(Some(callback), data);
|
||||||
|
HookId(num)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1420,26 +1573,6 @@ impl Emulator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(emulation_mode = "usermode")]
|
|
||||||
pub fn set_pre_syscall_hook(
|
|
||||||
&self,
|
|
||||||
hook: extern "C" fn(i32, u64, u64, u64, u64, u64, u64, u64, u64) -> SyscallHookResult,
|
|
||||||
) {
|
|
||||||
unsafe {
|
|
||||||
libafl_pre_syscall_hook = hook;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(emulation_mode = "usermode")]
|
|
||||||
pub fn set_post_syscall_hook(
|
|
||||||
&self,
|
|
||||||
hook: extern "C" fn(u64, i32, u64, u64, u64, u64, u64, u64, u64, u64) -> u64,
|
|
||||||
) {
|
|
||||||
unsafe {
|
|
||||||
libafl_post_syscall_hook = hook;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn add_gdb_cmd(&self, callback: Box<dyn FnMut(&Self, &str) -> bool>) {
|
pub fn add_gdb_cmd(&self, callback: Box<dyn FnMut(&Self, &str) -> bool>) {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -1519,6 +1652,7 @@ pub mod pybind {
|
|||||||
static mut PY_GENERIC_HOOKS: Vec<(GuestAddr, PyObject)> = vec![];
|
static mut PY_GENERIC_HOOKS: Vec<(GuestAddr, PyObject)> = vec![];
|
||||||
|
|
||||||
extern "C" fn py_syscall_hook_wrapper(
|
extern "C" fn py_syscall_hook_wrapper(
|
||||||
|
data: u64,
|
||||||
sys_num: i32,
|
sys_num: i32,
|
||||||
a0: u64,
|
a0: u64,
|
||||||
a1: u64,
|
a1: u64,
|
||||||
@ -1554,7 +1688,7 @@ pub mod pybind {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn py_generic_hook_wrapper(_pc: GuestAddr, idx: u64) {
|
extern "C" fn py_generic_hook_wrapper(idx: u64, _pc: GuestAddr) {
|
||||||
let obj = unsafe { &PY_GENERIC_HOOKS[idx as usize].1 };
|
let obj = unsafe { &PY_GENERIC_HOOKS[idx as usize].1 };
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
obj.call0(py).expect("Error in the hook");
|
obj.call0(py).expect("Error in the hook");
|
||||||
@ -1678,7 +1812,7 @@ pub mod pybind {
|
|||||||
unsafe {
|
unsafe {
|
||||||
PY_SYSCALL_HOOK = Some(hook);
|
PY_SYSCALL_HOOK = Some(hook);
|
||||||
}
|
}
|
||||||
self.emu.set_pre_syscall_hook(py_syscall_hook_wrapper);
|
self.emu.add_pre_syscall_hook(0u64, py_syscall_hook_wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_hook(&self, addr: GuestAddr, hook: PyObject) {
|
fn set_hook(&self, addr: GuestAddr, hook: PyObject) {
|
||||||
@ -1686,15 +1820,15 @@ pub mod pybind {
|
|||||||
let idx = PY_GENERIC_HOOKS.len();
|
let idx = PY_GENERIC_HOOKS.len();
|
||||||
PY_GENERIC_HOOKS.push((addr, hook));
|
PY_GENERIC_HOOKS.push((addr, hook));
|
||||||
self.emu
|
self.emu
|
||||||
.set_hook(addr, py_generic_hook_wrapper, idx as u64, true);
|
.set_hook(idx as u64, addr, py_generic_hook_wrapper, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_hook(&self, addr: GuestAddr) -> usize {
|
fn remove_hooks_at(&self, addr: GuestAddr) -> usize {
|
||||||
unsafe {
|
unsafe {
|
||||||
PY_GENERIC_HOOKS.retain(|(a, _)| *a != addr);
|
PY_GENERIC_HOOKS.retain(|(a, _)| *a != addr);
|
||||||
}
|
}
|
||||||
self.emu.remove_hook(addr, true)
|
self.emu.remove_hooks_at(addr, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ where
|
|||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
inner: InProcessExecutor<'a, H, OT, S>,
|
inner: InProcessExecutor<'a, H, OT, S>,
|
||||||
hooks: &'a mut QemuHooks<'a, QT, S>,
|
hooks: &'a mut QemuHooks<QT, S>,
|
||||||
first_exec: bool,
|
first_exec: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ where
|
|||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
pub fn new<EM, OF, Z>(
|
pub fn new<EM, OF, Z>(
|
||||||
hooks: &'a mut QemuHooks<'a, QT, S>,
|
hooks: &'a mut QemuHooks<QT, S>,
|
||||||
harness_fn: &'a mut H,
|
harness_fn: &'a mut H,
|
||||||
observers: OT,
|
observers: OT,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
@ -186,11 +186,11 @@ where
|
|||||||
&mut self.inner
|
&mut self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hooks(&self) -> &QemuHooks<'a, QT, S> {
|
pub fn hooks(&self) -> &QemuHooks<QT, S> {
|
||||||
self.hooks
|
self.hooks
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, QT, S> {
|
pub fn hooks_mut(&mut self) -> &mut QemuHooks<QT, S> {
|
||||||
self.hooks
|
self.hooks
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ where
|
|||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
{
|
{
|
||||||
first_exec: bool,
|
first_exec: bool,
|
||||||
hooks: &'a mut QemuHooks<'a, QT, S>,
|
hooks: &'a mut QemuHooks<QT, S>,
|
||||||
inner: InProcessForkExecutor<'a, H, OT, S, SP>,
|
inner: InProcessForkExecutor<'a, H, OT, S, SP>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +311,7 @@ where
|
|||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
{
|
{
|
||||||
pub fn new<EM, OF, Z>(
|
pub fn new<EM, OF, Z>(
|
||||||
hooks: &'a mut QemuHooks<'a, QT, S>,
|
hooks: &'a mut QemuHooks<QT, S>,
|
||||||
harness_fn: &'a mut H,
|
harness_fn: &'a mut H,
|
||||||
observers: OT,
|
observers: OT,
|
||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
@ -349,11 +349,11 @@ where
|
|||||||
&mut self.inner
|
&mut self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hooks(&self) -> &QemuHooks<'a, QT, S> {
|
pub fn hooks(&self) -> &QemuHooks<QT, S> {
|
||||||
self.hooks
|
self.hooks
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, QT, S> {
|
pub fn hooks_mut(&mut self) -> &mut QemuHooks<QT, S> {
|
||||||
self.hooks
|
self.hooks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,13 +16,13 @@ where
|
|||||||
{
|
{
|
||||||
const HOOKS_DO_SIDE_EFFECTS: bool = true;
|
const HOOKS_DO_SIDE_EFFECTS: bool = true;
|
||||||
|
|
||||||
fn init_hooks<QT>(&self, _hooks: &QemuHooks<'_, QT, S>)
|
fn init_hooks<QT>(&self, _hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_exec<QT>(&self, _hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec<QT>(&self, _hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
@ -48,11 +48,11 @@ where
|
|||||||
{
|
{
|
||||||
const HOOKS_DO_SIDE_EFFECTS: bool;
|
const HOOKS_DO_SIDE_EFFECTS: bool;
|
||||||
|
|
||||||
fn init_hooks_all<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn init_hooks_all<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>;
|
QT: QemuHelperTuple<S>;
|
||||||
|
|
||||||
fn first_exec_all<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec_all<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>;
|
QT: QemuHelperTuple<S>;
|
||||||
|
|
||||||
@ -74,13 +74,13 @@ where
|
|||||||
{
|
{
|
||||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||||
|
|
||||||
fn init_hooks_all<QT>(&self, _hooks: &QemuHooks<'_, QT, S>)
|
fn init_hooks_all<QT>(&self, _hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_exec_all<QT>(&self, _hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec_all<QT>(&self, _hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
@ -108,7 +108,7 @@ where
|
|||||||
{
|
{
|
||||||
const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS;
|
const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS;
|
||||||
|
|
||||||
fn init_hooks_all<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn init_hooks_all<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
@ -116,7 +116,7 @@ where
|
|||||||
self.1.init_hooks_all(hooks);
|
self.1.init_hooks_all(hooks);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_exec_all<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec_all<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@ use crate::SYS_newfstatat;
|
|||||||
use crate::{
|
use crate::{
|
||||||
emu::{Emulator, MmapPerms, SyscallHookResult},
|
emu::{Emulator, MmapPerms, SyscallHookResult},
|
||||||
helper::{QemuHelper, QemuHelperTuple},
|
helper::{QemuHelper, QemuHelperTuple},
|
||||||
hooks::QemuHooks,
|
hooks::{Hook, QemuHooks},
|
||||||
GuestAddr, SYS_fstat, SYS_fstatfs, SYS_futex, SYS_getrandom, SYS_mprotect, SYS_mremap,
|
GuestAddr, SYS_fstat, SYS_fstatfs, SYS_futex, SYS_getrandom, SYS_mprotect, SYS_mremap,
|
||||||
SYS_munmap, SYS_pread64, SYS_read, SYS_readlinkat, SYS_statfs,
|
SYS_munmap, SYS_pread64, SYS_read, SYS_readlinkat, SYS_statfs,
|
||||||
};
|
};
|
||||||
@ -487,23 +487,23 @@ impl<S> QemuHelper<S> for QemuSnapshotHelper
|
|||||||
where
|
where
|
||||||
S: UsesInput + HasMetadata,
|
S: UsesInput + HasMetadata,
|
||||||
{
|
{
|
||||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||||
where
|
where
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
hooks.writes(
|
hooks.writes(
|
||||||
None,
|
Hook::Empty,
|
||||||
Some(trace_write1_snapshot::<QT, S>),
|
Hook::Function(trace_write1_snapshot::<QT, S>),
|
||||||
Some(trace_write2_snapshot::<QT, S>),
|
Hook::Function(trace_write2_snapshot::<QT, S>),
|
||||||
Some(trace_write4_snapshot::<QT, S>),
|
Hook::Function(trace_write4_snapshot::<QT, S>),
|
||||||
Some(trace_write8_snapshot::<QT, S>),
|
Hook::Function(trace_write8_snapshot::<QT, S>),
|
||||||
Some(trace_write_n_snapshot::<QT, S>),
|
Hook::Function(trace_write_n_snapshot::<QT, S>),
|
||||||
);
|
);
|
||||||
|
|
||||||
if !self.accurate_unmap {
|
if !self.accurate_unmap {
|
||||||
hooks.syscalls(filter_mmap_snapshot::<QT, S>);
|
hooks.syscalls(Hook::Function(filter_mmap_snapshot::<QT, S>));
|
||||||
}
|
}
|
||||||
hooks.after_syscalls(trace_mmap_snapshot::<QT, S>);
|
hooks.after_syscalls(Hook::Function(trace_mmap_snapshot::<QT, S>));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_exec(&mut self, emulator: &Emulator, _input: &S::Input) {
|
fn pre_exec(&mut self, emulator: &Emulator, _input: &S::Input) {
|
||||||
@ -516,7 +516,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_write1_snapshot<QT, S>(
|
pub fn trace_write1_snapshot<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
_id: u64,
|
_id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -529,7 +529,7 @@ pub fn trace_write1_snapshot<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_write2_snapshot<QT, S>(
|
pub fn trace_write2_snapshot<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
_id: u64,
|
_id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -542,7 +542,7 @@ pub fn trace_write2_snapshot<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_write4_snapshot<QT, S>(
|
pub fn trace_write4_snapshot<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
_id: u64,
|
_id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -555,7 +555,7 @@ pub fn trace_write4_snapshot<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_write8_snapshot<QT, S>(
|
pub fn trace_write8_snapshot<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
_id: u64,
|
_id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -568,7 +568,7 @@ pub fn trace_write8_snapshot<QT, S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_write_n_snapshot<QT, S>(
|
pub fn trace_write_n_snapshot<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
_id: u64,
|
_id: u64,
|
||||||
addr: GuestAddr,
|
addr: GuestAddr,
|
||||||
@ -584,17 +584,17 @@ pub fn trace_write_n_snapshot<QT, S>(
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
pub fn filter_mmap_snapshot<QT, S>(
|
pub fn filter_mmap_snapshot<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
sys_num: i32,
|
sys_num: i32,
|
||||||
a0: u64,
|
a0: GuestAddr,
|
||||||
a1: u64,
|
a1: GuestAddr,
|
||||||
_a2: u64,
|
_a2: GuestAddr,
|
||||||
_a3: u64,
|
_a3: GuestAddr,
|
||||||
_a4: u64,
|
_a4: GuestAddr,
|
||||||
_a5: u64,
|
_a5: GuestAddr,
|
||||||
_a6: u64,
|
_a6: GuestAddr,
|
||||||
_a7: u64,
|
_a7: GuestAddr,
|
||||||
) -> SyscallHookResult
|
) -> SyscallHookResult
|
||||||
where
|
where
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
@ -612,19 +612,19 @@ where
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
pub fn trace_mmap_snapshot<QT, S>(
|
pub fn trace_mmap_snapshot<QT, S>(
|
||||||
hooks: &mut QemuHooks<'_, QT, S>,
|
hooks: &mut QemuHooks<QT, S>,
|
||||||
_state: Option<&mut S>,
|
_state: Option<&mut S>,
|
||||||
result: u64,
|
result: GuestAddr,
|
||||||
sys_num: i32,
|
sys_num: i32,
|
||||||
a0: u64,
|
a0: GuestAddr,
|
||||||
a1: u64,
|
a1: GuestAddr,
|
||||||
a2: u64,
|
a2: GuestAddr,
|
||||||
a3: u64,
|
a3: GuestAddr,
|
||||||
_a4: u64,
|
_a4: GuestAddr,
|
||||||
_a5: u64,
|
_a5: GuestAddr,
|
||||||
_a6: u64,
|
_a6: GuestAddr,
|
||||||
_a7: u64,
|
_a7: GuestAddr,
|
||||||
) -> u64
|
) -> GuestAddr
|
||||||
where
|
where
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
@ -633,15 +633,15 @@ where
|
|||||||
match i64::from(sys_num) {
|
match i64::from(sys_num) {
|
||||||
SYS_read | SYS_pread64 => {
|
SYS_read | SYS_pread64 => {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
h.access(a1 as GuestAddr, a2 as usize);
|
h.access(a1, a2 as usize);
|
||||||
}
|
}
|
||||||
SYS_readlinkat => {
|
SYS_readlinkat => {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
h.access(a2 as GuestAddr, a3 as usize);
|
h.access(a2, a3 as usize);
|
||||||
}
|
}
|
||||||
SYS_futex => {
|
SYS_futex => {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
h.access(a0 as GuestAddr, a3 as usize);
|
h.access(a0, a3 as usize);
|
||||||
}
|
}
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(
|
||||||
cpu_target = "arm",
|
cpu_target = "arm",
|
||||||
@ -652,27 +652,27 @@ where
|
|||||||
SYS_newfstatat => {
|
SYS_newfstatat => {
|
||||||
if a2 != 0 {
|
if a2 != 0 {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
h.access(a2 as GuestAddr, 4096); // stat is not greater than a page
|
h.access(a2, 4096); // stat is not greater than a page
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(any(cpu_target = "arm", cpu_target = "mips", cpu_target = "i386"))]
|
#[cfg(any(cpu_target = "arm", cpu_target = "mips", cpu_target = "i386"))]
|
||||||
SYS_fstatat64 => {
|
SYS_fstatat64 => {
|
||||||
if a2 != 0 {
|
if a2 != 0 {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
h.access(a2 as GuestAddr, 4096); // stat is not greater than a page
|
h.access(a2, 4096); // stat is not greater than a page
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SYS_statfs | SYS_fstatfs | SYS_fstat => {
|
SYS_statfs | SYS_fstatfs | SYS_fstat => {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
h.access(a1 as GuestAddr, 4096); // stat is not greater than a page
|
h.access(a1, 4096); // stat is not greater than a page
|
||||||
}
|
}
|
||||||
SYS_getrandom => {
|
SYS_getrandom => {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
h.access(a0 as GuestAddr, a1 as usize);
|
h.access(a0, a1 as usize);
|
||||||
}
|
}
|
||||||
// mmap syscalls
|
// mmap syscalls
|
||||||
sys_const => {
|
sys_const => {
|
||||||
if result as GuestAddr == GuestAddr::MAX
|
if result == GuestAddr::MAX
|
||||||
/* -1 */
|
/* -1 */
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
@ -684,7 +684,7 @@ where
|
|||||||
if sys_const == SYS_mmap2 {
|
if sys_const == SYS_mmap2 {
|
||||||
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
h.add_mapped(result as GuestAddr, a1 as usize, Some(prot));
|
h.add_mapped(result, a1 as usize, Some(prot));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -692,24 +692,24 @@ where
|
|||||||
if sys_const == SYS_mmap {
|
if sys_const == SYS_mmap {
|
||||||
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
h.add_mapped(result as GuestAddr, a1 as usize, Some(prot));
|
h.add_mapped(result, a1 as usize, Some(prot));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sys_const == SYS_mremap {
|
if sys_const == SYS_mremap {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
// TODO get the old permissions from the removed mapping
|
// TODO get the old permissions from the removed mapping
|
||||||
h.remove_mapped(a0 as GuestAddr, a1 as usize);
|
h.remove_mapped(a0, a1 as usize);
|
||||||
h.add_mapped(result as GuestAddr, a2 as usize, None);
|
h.add_mapped(result, a2 as usize, None);
|
||||||
} else if sys_const == SYS_mprotect {
|
} else if sys_const == SYS_mprotect {
|
||||||
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
h.add_mapped(a0 as GuestAddr, a1 as usize, Some(prot));
|
h.add_mapped(a0, a1 as usize, Some(prot));
|
||||||
}
|
}
|
||||||
} else if sys_const == SYS_munmap {
|
} else if sys_const == SYS_munmap {
|
||||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||||
if !h.accurate_unmap && !h.is_unmap_allowed(a0 as GuestAddr, a1 as usize) {
|
if !h.accurate_unmap && !h.is_unmap_allowed(a0, a1 as usize) {
|
||||||
h.remove_mapped(a0 as GuestAddr, a1 as usize);
|
h.remove_mapped(a0, a1 as usize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ where
|
|||||||
|
|
||||||
if self.use_cmplog.unwrap_or(false) {
|
if self.use_cmplog.unwrap_or(false) {
|
||||||
let mut hooks = QemuHooks::new(
|
let mut hooks = QemuHooks::new(
|
||||||
emulator,
|
emulator.clone(),
|
||||||
#[cfg(not(any(feature = "mips", feature = "hexagon")))]
|
#[cfg(not(any(feature = "mips", feature = "hexagon")))]
|
||||||
tuple_list!(
|
tuple_list!(
|
||||||
QemuEdgeCoverageHelper::default(),
|
QemuEdgeCoverageHelper::default(),
|
||||||
@ -325,8 +325,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut hooks =
|
let mut hooks = QemuHooks::new(
|
||||||
QemuHooks::new(emulator, tuple_list!(QemuEdgeCoverageHelper::default()));
|
emulator.clone(),
|
||||||
|
tuple_list!(QemuEdgeCoverageHelper::default()),
|
||||||
|
);
|
||||||
|
|
||||||
let executor = QemuExecutor::new(
|
let executor = QemuExecutor::new(
|
||||||
&mut hooks,
|
&mut hooks,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user