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(
|
||||
&emu,
|
||||
emu.clone(),
|
||||
tuple_list!(
|
||||
QemuEdgeCoverageChildHelper::default(),
|
||||
QemuCmpLogChildHelper::default(),
|
||||
|
@ -45,15 +45,15 @@ use libafl_bolts::{
|
||||
AsSlice,
|
||||
};
|
||||
use libafl_qemu::{
|
||||
cmplog::{CmpLogObserver, QemuCmpLogHelper},
|
||||
// asan::{init_with_asan, QemuAsanHelper},
|
||||
cmplog::{CmpLogObserver, QemuCmpLogHelper},
|
||||
edges::edges_map_mut_slice,
|
||||
edges::QemuEdgeCoverageHelper,
|
||||
edges::MAX_EDGES_NUM,
|
||||
elf::EasyElf,
|
||||
emu::Emulator,
|
||||
filter_qemu_args,
|
||||
hooks::QemuHooks,
|
||||
Emulator,
|
||||
GuestReg,
|
||||
//snapshot::QemuSnapshotHelper,
|
||||
MmapPerms,
|
||||
@ -173,7 +173,7 @@ fn fuzz(
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let env: Vec<(String, String)> = env::vars().collect();
|
||||
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 elf = EasyElf::from_file(emu.binary_path(), &mut elf_buffer)?;
|
||||
@ -342,11 +342,11 @@ fn fuzz(
|
||||
};
|
||||
|
||||
let mut hooks = QemuHooks::new(
|
||||
&emu,
|
||||
emu.clone(),
|
||||
tuple_list!(
|
||||
QemuEdgeCoverageHelper::default(),
|
||||
QemuCmpLogHelper::default(),
|
||||
//QemuAsanHelper::default(),
|
||||
// QemuAsanHelper::default(asan),
|
||||
//QemuSnapshotHelper::new()
|
||||
),
|
||||
);
|
||||
|
@ -215,7 +215,10 @@ pub fn fuzz() -> Result<(), Error> {
|
||||
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(
|
||||
&mut hooks,
|
||||
|
@ -236,7 +236,7 @@ pub fn fuzz() {
|
||||
coverage.set_file_name(format!("{coverage_name}-{core:03}.{coverage_extension}"));
|
||||
|
||||
let mut hooks = QemuHooks::new(
|
||||
&emu,
|
||||
emu.clone(),
|
||||
tuple_list!(QemuDrCovHelper::new(
|
||||
QemuInstrumentationFilter::None,
|
||||
rangemap,
|
||||
|
@ -103,11 +103,12 @@ impl<'a> Client<'a> {
|
||||
let mut env = self.env()?;
|
||||
log::debug!("ENV: {:#?}", env);
|
||||
|
||||
let emu = {
|
||||
let (emu, mut asan) = {
|
||||
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 {
|
||||
Emulator::new(&args, &env)?
|
||||
(Emulator::new(&args, &env)?, None)
|
||||
}
|
||||
};
|
||||
|
||||
@ -136,11 +137,14 @@ impl<'a> Client<'a> {
|
||||
let helpers = tuple_list!(
|
||||
edge_coverage_helper,
|
||||
QemuCmpLogHelper::default(),
|
||||
QemuAsanHelper::default(),
|
||||
QemuAsanHelper::default(asan.take().unwrap()),
|
||||
);
|
||||
instance.build().run(helpers, state)
|
||||
} 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)
|
||||
} else if is_cmplog {
|
||||
let helpers = tuple_list!(edge_coverage_helper, QemuCmpLogHelper::default(),);
|
||||
|
@ -59,7 +59,7 @@ impl<'a> Instance<'a> {
|
||||
where
|
||||
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
|
||||
let edges_observer = unsafe {
|
||||
|
@ -192,7 +192,7 @@ pub fn fuzz() {
|
||||
// A fuzzer with feedbacks and a corpus scheduler
|
||||
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
|
||||
let mut executor = QemuExecutor::new(
|
||||
|
@ -65,6 +65,7 @@ rangemap = "1.3"
|
||||
log = "0.4.20"
|
||||
addr2line = "0.21"
|
||||
typed-arena = "2.0"
|
||||
paste = "1"
|
||||
enum-map = "2.7"
|
||||
|
||||
pyo3 = { version = "0.18", optional = true }
|
||||
|
@ -32,3 +32,4 @@ json = "0.12"
|
||||
shell-words = "1.1"
|
||||
pkg-config = "0.3.26"
|
||||
cc = "1.0"
|
||||
regex = "1"
|
||||
|
@ -77,6 +77,7 @@ const WRAPPER_HEADER: &str = r#"
|
||||
#include "qemu/plugin-memory.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_sync_backdoor")
|
||||
.allowlist_type("libafl_exit_reason_breakpoint")
|
||||
.allowlist_type("Syx.*")
|
||||
.allowlist_function("qemu_user_init")
|
||||
.allowlist_function("target_mmap")
|
||||
.allowlist_function("target_mprotect")
|
||||
@ -128,12 +130,9 @@ pub fn generate(
|
||||
.allowlist_function("qemu_plugin_hwaddr_phys_addr")
|
||||
.allowlist_function("qemu_plugin_get_hwaddr")
|
||||
.allowlist_function("qemu_target_page_size")
|
||||
.allowlist_function("syx_snapshot_init")
|
||||
.allowlist_function("syx_snapshot_new")
|
||||
.allowlist_function("syx_snapshot_root_restore")
|
||||
.allowlist_function("syx_snapshot_dirty_list_add")
|
||||
.allowlist_function("syx_.*")
|
||||
.allowlist_function("device_list_all")
|
||||
.allowlist_function("libafl_get_exit_reason")
|
||||
.allowlist_function("libafl_.*")
|
||||
.blocklist_function("main_loop_wait") // bindgen issue #1313
|
||||
.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_DIRNAME: &str = "qemu-libafl-bridge";
|
||||
const QEMU_REVISION: &str = "8db5524416b52c999459f1fe3373846bdcb23ac1";
|
||||
const QEMU_REVISION: &str = "6a63c7f7924d3db1dfff99e7b6cf460e8fb35785";
|
||||
|
||||
fn build_dep_check(tools: &[&str]) {
|
||||
for tool in tools {
|
||||
|
@ -5,6 +5,7 @@ use std::{
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use regex::Regex;
|
||||
use which::which;
|
||||
|
||||
mod bindings;
|
||||
@ -28,6 +29,13 @@ pub fn build_with_bindings(
|
||||
.expect("Failed to generate the bindings");
|
||||
bind.write_to_file(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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -22,7 +22,7 @@ use crate::{
|
||||
calls::FullBacktraceCollector,
|
||||
emu::{EmuError, Emulator, MemAccessInfo, SyscallHookResult},
|
||||
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
hooks::QemuHooks,
|
||||
hooks::{Hook, QemuHooks},
|
||||
GuestAddr, Regs,
|
||||
};
|
||||
|
||||
@ -61,6 +61,14 @@ pub enum QasanAction {
|
||||
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)]
|
||||
#[repr(i8)]
|
||||
pub enum PoisonKind {
|
||||
@ -143,7 +151,7 @@ impl AllocTreeItem {
|
||||
self.allocated = false;
|
||||
}
|
||||
}
|
||||
|
||||
use std::pin::Pin;
|
||||
pub struct AsanGiovese {
|
||||
pub alloc_tree: Mutex<IntervalTree<GuestAddr, AllocTreeItem>>,
|
||||
pub saved_tree: IntervalTree<GuestAddr, AllocTreeItem>,
|
||||
@ -163,7 +171,7 @@ impl core::fmt::Debug for AsanGiovese {
|
||||
}
|
||||
|
||||
impl AsanGiovese {
|
||||
pub unsafe fn map_shadow() {
|
||||
unsafe fn map_shadow() {
|
||||
assert!(
|
||||
libc::mmap(
|
||||
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]
|
||||
#[must_use]
|
||||
pub fn is_invalid_access_1(emu: &Emulator, addr: GuestAddr) -> bool {
|
||||
@ -357,7 +439,7 @@ impl AsanGiovese {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unpoison_page(emu: &Emulator, page: GuestAddr) {
|
||||
pub fn unpoison_page(emu: &Emulator, page: GuestAddr) {
|
||||
unsafe {
|
||||
let h = emu.g2h::<*const c_void>(page) as isize;
|
||||
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) {
|
||||
if let Some(mut cb) = self.error_callback.take() {
|
||||
(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) {
|
||||
if self.snapshot_shadow {
|
||||
let set = self.dirty_shadow.lock().unwrap();
|
||||
@ -599,7 +666,7 @@ static mut ASAN_INITED: bool = false;
|
||||
pub fn init_with_asan(
|
||||
args: &mut Vec<String>,
|
||||
env: &mut [(String, String)],
|
||||
) -> Result<Emulator, EmuError> {
|
||||
) -> Result<(Emulator, Pin<Box<AsanGiovese>>), EmuError> {
|
||||
let current = env::current_exe().unwrap();
|
||||
let asan_lib = fs::canonicalize(current)
|
||||
.unwrap()
|
||||
@ -644,7 +711,11 @@ pub fn init_with_asan(
|
||||
AsanGiovese::map_shadow();
|
||||
ASAN_INITED = true;
|
||||
}
|
||||
Emulator::new(args, env)
|
||||
|
||||
let emu = Emulator::new(args, env)?;
|
||||
let rt = AsanGiovese::new(&emu);
|
||||
|
||||
Ok((emu, rt))
|
||||
}
|
||||
|
||||
pub enum QemuAsanOptions {
|
||||
@ -661,13 +732,26 @@ pub struct QemuAsanHelper {
|
||||
enabled: bool,
|
||||
detect_leaks: bool,
|
||||
empty: bool,
|
||||
rt: AsanGiovese,
|
||||
rt: Pin<Box<AsanGiovese>>,
|
||||
filter: QemuInstrumentationFilter,
|
||||
}
|
||||
|
||||
impl QemuAsanHelper {
|
||||
#[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(...)");
|
||||
let (snapshot, detect_leaks) = match options {
|
||||
QemuAsanOptions::None => (false, false),
|
||||
@ -675,17 +759,19 @@ impl QemuAsanHelper {
|
||||
QemuAsanOptions::DetectLeaks => (false, true),
|
||||
QemuAsanOptions::SnapshotDetectLeaks => (true, true),
|
||||
};
|
||||
rt.set_snapshot_shadow(snapshot);
|
||||
Self {
|
||||
enabled: true,
|
||||
detect_leaks,
|
||||
empty: true,
|
||||
rt: AsanGiovese::new(snapshot),
|
||||
rt,
|
||||
filter,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_error_callback(
|
||||
mut rt: Pin<Box<AsanGiovese>>,
|
||||
filter: QemuInstrumentationFilter,
|
||||
error_callback: AsanErrorCallback,
|
||||
options: QemuAsanOptions,
|
||||
@ -697,18 +783,24 @@ impl QemuAsanHelper {
|
||||
QemuAsanOptions::DetectLeaks => (false, true),
|
||||
QemuAsanOptions::SnapshotDetectLeaks => (true, true),
|
||||
};
|
||||
rt.set_snapshot_shadow(snapshot);
|
||||
rt.set_error_callback(error_callback);
|
||||
Self {
|
||||
enabled: true,
|
||||
detect_leaks,
|
||||
empty: true,
|
||||
rt: AsanGiovese::with_error_callback(snapshot, error_callback),
|
||||
rt,
|
||||
filter,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_asan_report(filter: QemuInstrumentationFilter, options: QemuAsanOptions) -> Self {
|
||||
Self::with_error_callback(filter, Box::new(asan_report), options)
|
||||
pub fn with_asan_report(
|
||||
rt: Pin<Box<AsanGiovese>>,
|
||||
filter: QemuInstrumentationFilter,
|
||||
options: QemuAsanOptions,
|
||||
) -> Self {
|
||||
Self::with_error_callback(rt, filter, Box::new(asan_report), options)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@ -726,12 +818,11 @@ impl QemuAsanHelper {
|
||||
}
|
||||
|
||||
pub fn alloc(&mut self, pc: GuestAddr, start: GuestAddr, end: GuestAddr) {
|
||||
self.rt.alloc_remove(start, end);
|
||||
self.rt.alloc_insert(pc, start, end);
|
||||
self.rt.allocation(pc, start, end);
|
||||
}
|
||||
|
||||
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)]
|
||||
@ -830,12 +921,6 @@ impl QemuAsanHelper {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for QemuAsanHelper {
|
||||
fn default() -> Self {
|
||||
Self::new(QemuInstrumentationFilter::None, QemuAsanOptions::Snapshot)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasInstrumentationFilter for QemuAsanHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationFilter {
|
||||
&self.filter
|
||||
@ -852,37 +937,37 @@ where
|
||||
{
|
||||
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
|
||||
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() {
|
||||
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
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
hooks.reads(
|
||||
Some(gen_readwrite_asan::<QT, S>),
|
||||
Some(trace_read1_asan::<QT, S>),
|
||||
Some(trace_read2_asan::<QT, S>),
|
||||
Some(trace_read4_asan::<QT, S>),
|
||||
Some(trace_read8_asan::<QT, S>),
|
||||
Some(trace_read_n_asan::<QT, S>),
|
||||
Hook::Function(gen_readwrite_asan::<QT, S>),
|
||||
Hook::Function(trace_read1_asan::<QT, S>),
|
||||
Hook::Function(trace_read2_asan::<QT, S>),
|
||||
Hook::Function(trace_read4_asan::<QT, S>),
|
||||
Hook::Function(trace_read8_asan::<QT, S>),
|
||||
Hook::Function(trace_read_n_asan::<QT, S>),
|
||||
);
|
||||
|
||||
hooks.writes(
|
||||
Some(gen_readwrite_asan::<QT, S>),
|
||||
Some(trace_write1_asan::<QT, S>),
|
||||
Some(trace_write2_asan::<QT, S>),
|
||||
Some(trace_write4_asan::<QT, S>),
|
||||
Some(trace_write8_asan::<QT, S>),
|
||||
Some(trace_write_n_asan::<QT, S>),
|
||||
Hook::Function(gen_readwrite_asan::<QT, S>),
|
||||
Hook::Function(trace_write1_asan::<QT, S>),
|
||||
Hook::Function(trace_write2_asan::<QT, S>),
|
||||
Hook::Function(trace_write4_asan::<QT, S>),
|
||||
Hook::Function(trace_write8_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
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
@ -920,7 +1005,7 @@ where
|
||||
}
|
||||
|
||||
pub fn gen_readwrite_asan<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
_info: MemAccessInfo,
|
||||
@ -938,7 +1023,7 @@ where
|
||||
}
|
||||
|
||||
pub fn trace_read1_asan<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -952,7 +1037,7 @@ pub fn trace_read1_asan<QT, S>(
|
||||
}
|
||||
|
||||
pub fn trace_read2_asan<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -966,7 +1051,7 @@ pub fn trace_read2_asan<QT, S>(
|
||||
}
|
||||
|
||||
pub fn trace_read4_asan<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -980,7 +1065,7 @@ pub fn trace_read4_asan<QT, S>(
|
||||
}
|
||||
|
||||
pub fn trace_read8_asan<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -994,7 +1079,7 @@ pub fn trace_read8_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>,
|
||||
id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -1009,7 +1094,7 @@ pub fn trace_read_n_asan<QT, S>(
|
||||
}
|
||||
|
||||
pub fn trace_write1_asan<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -1023,7 +1108,7 @@ pub fn trace_write1_asan<QT, S>(
|
||||
}
|
||||
|
||||
pub fn trace_write2_asan<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -1037,7 +1122,7 @@ pub fn trace_write2_asan<QT, S>(
|
||||
}
|
||||
|
||||
pub fn trace_write4_asan<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -1051,7 +1136,7 @@ pub fn trace_write4_asan<QT, S>(
|
||||
}
|
||||
|
||||
pub fn trace_write8_asan<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -1065,7 +1150,7 @@ pub fn trace_write8_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>,
|
||||
id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -1081,17 +1166,17 @@ pub fn trace_write_n_asan<QT, S>(
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn qasan_fake_syscall<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
sys_num: i32,
|
||||
a0: u64,
|
||||
a1: u64,
|
||||
a2: u64,
|
||||
a3: u64,
|
||||
_a4: u64,
|
||||
_a5: u64,
|
||||
_a6: u64,
|
||||
_a7: u64,
|
||||
a0: GuestAddr,
|
||||
a1: GuestAddr,
|
||||
a2: GuestAddr,
|
||||
_a3: GuestAddr,
|
||||
_a4: GuestAddr,
|
||||
_a5: GuestAddr,
|
||||
_a6: GuestAddr,
|
||||
_a7: GuestAddr,
|
||||
) -> SyscallHookResult
|
||||
where
|
||||
S: UsesInput,
|
||||
@ -1100,42 +1185,14 @@ where
|
||||
if sys_num == QASAN_FAKESYS_NR {
|
||||
let emulator = hooks.emulator().clone();
|
||||
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
|
||||
let mut r = 0;
|
||||
match QasanAction::try_from(a0).expect("Invalid QASan action number") {
|
||||
QasanAction::CheckLoad => {
|
||||
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 => {
|
||||
let pc: GuestAddr = emulator.read_reg(Regs::Pc).unwrap();
|
||||
h.write_n(&emulator, pc, a1 as GuestAddr, 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);
|
||||
h.write_n(&emulator, pc, a1, a2 as usize);
|
||||
}
|
||||
QasanAction::Enable => {
|
||||
h.set_enabled(true);
|
||||
@ -1146,8 +1203,9 @@ where
|
||||
QasanAction::SwapState => {
|
||||
h.set_enabled(!h.enabled());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
SyscallHookResult::new(Some(r))
|
||||
SyscallHookResult::new(Some(0))
|
||||
} else {
|
||||
SyscallHookResult::new(None)
|
||||
}
|
||||
|
@ -13,14 +13,14 @@ use crate::{
|
||||
capstone,
|
||||
emu::{ArchExtras, Emulator},
|
||||
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
hooks::QemuHooks,
|
||||
hooks::{Hook, QemuHooks},
|
||||
GuestAddr,
|
||||
};
|
||||
|
||||
pub trait CallTraceCollector: 'static + Debug {
|
||||
fn on_call<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
call_len: usize,
|
||||
@ -30,7 +30,7 @@ pub trait CallTraceCollector: 'static + Debug {
|
||||
|
||||
fn on_ret<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
ret_addr: GuestAddr,
|
||||
@ -61,7 +61,7 @@ pub trait CallTraceCollector: 'static + Debug {
|
||||
pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug {
|
||||
fn on_call_all<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
call_len: usize,
|
||||
@ -71,7 +71,7 @@ pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug {
|
||||
|
||||
fn on_ret_all<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_pc: GuestAddr,
|
||||
ret_addr: GuestAddr,
|
||||
@ -97,7 +97,7 @@ pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug {
|
||||
impl CallTraceCollectorTuple for () {
|
||||
fn on_call_all<QT, S>(
|
||||
&mut self,
|
||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_pc: GuestAddr,
|
||||
_call_len: usize,
|
||||
@ -109,7 +109,7 @@ impl CallTraceCollectorTuple for () {
|
||||
|
||||
fn on_ret_all<QT, S>(
|
||||
&mut self,
|
||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_pc: GuestAddr,
|
||||
_ret_addr: GuestAddr,
|
||||
@ -145,7 +145,7 @@ where
|
||||
{
|
||||
fn on_call_all<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
mut state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
call_len: usize,
|
||||
@ -167,7 +167,7 @@ where
|
||||
|
||||
fn on_ret_all<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
mut state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
ret_addr: GuestAddr,
|
||||
@ -238,7 +238,7 @@ where
|
||||
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
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
@ -267,7 +267,7 @@ where
|
||||
}
|
||||
|
||||
fn gen_blocks_calls<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
) -> Option<u64>
|
||||
@ -319,9 +319,8 @@ where
|
||||
capstone::InsnGroupType::CS_GRP_CALL => {
|
||||
let call_len = insn.bytes().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>,
|
||||
state: Option<&mut S>,
|
||||
pc| {
|
||||
let call_cb = Box::new(
|
||||
move |hooks: &mut QemuHooks<QT, S>, state: Option<&mut S>, pc| {
|
||||
// eprintln!("CALL @ 0x{:#x}", pc + call_len);
|
||||
let mut collectors = if let Some(h) =
|
||||
hooks.helpers_mut().match_first_type_mut::<Self>()
|
||||
@ -342,17 +341,16 @@ where
|
||||
.match_first_type_mut::<Self>()
|
||||
.unwrap()
|
||||
.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 => {
|
||||
hooks.instruction(insn.address() as GuestAddr, Self::on_ret, false);
|
||||
hooks.instruction_function(
|
||||
insn.address() as GuestAddr,
|
||||
Self::on_ret,
|
||||
false,
|
||||
);
|
||||
break 'disasm;
|
||||
}
|
||||
capstone::InsnGroupType::CS_GRP_INVALID
|
||||
@ -400,11 +398,15 @@ where
|
||||
S: UsesInput,
|
||||
T: CallTraceCollectorTuple,
|
||||
{
|
||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||
where
|
||||
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) {
|
||||
@ -468,7 +470,7 @@ impl CallTraceCollector for OnCrashBacktraceCollector {
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
fn on_call<QT, S>(
|
||||
&mut self,
|
||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
call_len: usize,
|
||||
@ -482,7 +484,7 @@ impl CallTraceCollector for OnCrashBacktraceCollector {
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
fn on_ret<QT, S>(
|
||||
&mut self,
|
||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_pc: GuestAddr,
|
||||
ret_addr: GuestAddr,
|
||||
@ -557,7 +559,7 @@ impl CallTraceCollector for FullBacktraceCollector {
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
fn on_call<QT, S>(
|
||||
&mut self,
|
||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
call_len: usize,
|
||||
@ -574,7 +576,7 @@ impl CallTraceCollector for FullBacktraceCollector {
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
fn on_ret<QT, S>(
|
||||
&mut self,
|
||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_pc: GuestAddr,
|
||||
ret_addr: GuestAddr,
|
||||
|
@ -20,7 +20,7 @@ use crate::{
|
||||
helper::{
|
||||
hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter,
|
||||
},
|
||||
hooks::QemuHooks,
|
||||
hooks::{Hook, QemuHooks},
|
||||
GuestAddr,
|
||||
};
|
||||
|
||||
@ -83,16 +83,16 @@ impl<S> QemuHelper<S> for QemuCmpLogHelper
|
||||
where
|
||||
S: UsesInput + HasMetadata,
|
||||
{
|
||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
||||
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
hooks.cmps_raw(
|
||||
Some(gen_unique_cmp_ids::<QT, S>),
|
||||
Some(trace_cmp1_cmplog),
|
||||
Some(trace_cmp2_cmplog),
|
||||
Some(trace_cmp4_cmplog),
|
||||
Some(trace_cmp8_cmplog),
|
||||
hooks.cmps(
|
||||
Hook::Function(gen_unique_cmp_ids::<QT, S>),
|
||||
Hook::Raw(trace_cmp1_cmplog),
|
||||
Hook::Raw(trace_cmp2_cmplog),
|
||||
Hook::Raw(trace_cmp4_cmplog),
|
||||
Hook::Raw(trace_cmp8_cmplog),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -127,22 +127,22 @@ where
|
||||
{
|
||||
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
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
hooks.cmps_raw(
|
||||
Some(gen_hashed_cmp_ids::<QT, S>),
|
||||
Some(trace_cmp1_cmplog),
|
||||
Some(trace_cmp2_cmplog),
|
||||
Some(trace_cmp4_cmplog),
|
||||
Some(trace_cmp8_cmplog),
|
||||
hooks.cmps(
|
||||
Hook::Function(gen_hashed_cmp_ids::<QT, S>),
|
||||
Hook::Raw(trace_cmp1_cmplog),
|
||||
Hook::Raw(trace_cmp2_cmplog),
|
||||
Hook::Raw(trace_cmp4_cmplog),
|
||||
Hook::Raw(trace_cmp8_cmplog),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_unique_cmp_ids<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
_size: usize,
|
||||
@ -174,7 +174,7 @@ where
|
||||
}
|
||||
|
||||
pub fn gen_hashed_cmp_ids<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
_size: usize,
|
||||
@ -192,25 +192,25 @@ where
|
||||
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 {
|
||||
__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 {
|
||||
__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 {
|
||||
__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 {
|
||||
__libafl_targets_cmplog_instructions(id as usize, 8, v0, v1);
|
||||
}
|
||||
@ -238,7 +238,7 @@ impl QemuCmpLogRoutinesHelper {
|
||||
self.filter.allowed(addr)
|
||||
}
|
||||
|
||||
extern "C" fn on_call(_pc: GuestAddr, k: u64) {
|
||||
extern "C" fn on_call(k: u64, _pc: GuestAddr) {
|
||||
unsafe {
|
||||
if CMPLOG_ENABLED == 0 {
|
||||
return;
|
||||
@ -266,7 +266,7 @@ impl QemuCmpLogRoutinesHelper {
|
||||
}
|
||||
|
||||
fn gen_blocks_calls<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
) -> Option<u64>
|
||||
@ -317,7 +317,7 @@ impl QemuCmpLogRoutinesHelper {
|
||||
match u32::from(detail.0) {
|
||||
capstone::InsnGroupType::CS_GRP_CALL => {
|
||||
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_INVALID
|
||||
@ -363,10 +363,14 @@ impl<S> QemuHelper<S> for QemuCmpLogRoutinesHelper
|
||||
where
|
||||
S: UsesInput,
|
||||
{
|
||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
||||
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||
where
|
||||
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::{
|
||||
emu::{GuestAddr, GuestUsize},
|
||||
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
hooks::QemuHooks,
|
||||
hooks::{Hook, QemuHooks},
|
||||
Emulator,
|
||||
};
|
||||
|
||||
@ -89,14 +89,14 @@ impl<S> QemuHelper<S> for QemuDrCovHelper
|
||||
where
|
||||
S: UsesInput + HasMetadata,
|
||||
{
|
||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
hooks.blocks(
|
||||
Some(gen_unique_block_ids::<QT, S>),
|
||||
Some(gen_block_lengths::<QT, S>),
|
||||
Some(exec_trace_block::<QT, S>),
|
||||
Hook::Function(gen_unique_block_ids::<QT, S>),
|
||||
Hook::Function(gen_block_lengths::<QT, S>),
|
||||
Hook::Function(exec_trace_block::<QT, S>),
|
||||
);
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ where
|
||||
}
|
||||
|
||||
pub fn gen_unique_block_ids<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
) -> Option<u64>
|
||||
@ -247,7 +247,7 @@ where
|
||||
}
|
||||
|
||||
pub fn gen_block_lengths<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
block_length: GuestUsize,
|
||||
@ -271,7 +271,7 @@ pub fn gen_block_lengths<QT, S>(
|
||||
.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
|
||||
S: HasMetadata,
|
||||
S: UsesInput,
|
||||
|
@ -13,7 +13,7 @@ use crate::{
|
||||
helper::{
|
||||
hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter,
|
||||
},
|
||||
hooks::QemuHooks,
|
||||
hooks::{Hook, QemuHooks},
|
||||
};
|
||||
|
||||
#[cfg_attr(
|
||||
@ -87,17 +87,20 @@ impl<S> QemuHelper<S> for QemuEdgeCoverageHelper
|
||||
where
|
||||
S: UsesInput + HasMetadata,
|
||||
{
|
||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
||||
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
if self.use_hitcounts {
|
||||
hooks.edges_raw(
|
||||
Some(gen_unique_edge_ids::<QT, S>),
|
||||
Some(trace_edge_hitcount),
|
||||
hooks.edges(
|
||||
Hook::Function(gen_unique_edge_ids::<QT, S>),
|
||||
Hook::Raw(trace_edge_hitcount),
|
||||
);
|
||||
} 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;
|
||||
|
||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
||||
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
if self.use_hitcounts {
|
||||
hooks.edges_raw(
|
||||
Some(gen_hashed_edge_ids::<QT, S>),
|
||||
Some(trace_edge_hitcount_ptr),
|
||||
hooks.edges(
|
||||
Hook::Function(gen_hashed_edge_ids::<QT, S>),
|
||||
Hook::Raw(trace_edge_hitcount_ptr),
|
||||
);
|
||||
} else {
|
||||
hooks.edges_raw(
|
||||
Some(gen_hashed_edge_ids::<QT, S>),
|
||||
Some(trace_edge_single_ptr),
|
||||
hooks.edges(
|
||||
Hook::Function(gen_hashed_edge_ids::<QT, S>),
|
||||
Hook::Raw(trace_edge_single_ptr),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -226,21 +229,21 @@ where
|
||||
{
|
||||
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
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
if self.use_hitcounts {
|
||||
hooks.blocks_raw(
|
||||
Some(gen_hashed_block_ids::<QT, S>),
|
||||
None,
|
||||
Some(trace_block_transition_hitcount),
|
||||
hooks.blocks(
|
||||
Hook::Function(gen_hashed_block_ids::<QT, S>),
|
||||
Hook::Empty,
|
||||
Hook::Raw(trace_block_transition_hitcount),
|
||||
);
|
||||
} else {
|
||||
hooks.blocks_raw(
|
||||
Some(gen_hashed_block_ids::<QT, S>),
|
||||
None,
|
||||
Some(trace_block_transition_single),
|
||||
hooks.blocks(
|
||||
Hook::Function(gen_hashed_block_ids::<QT, S>),
|
||||
Hook::Empty,
|
||||
Hook::Raw(trace_block_transition_single),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -249,7 +252,7 @@ where
|
||||
thread_local!(static PREV_LOC : UnsafeCell<u64> = UnsafeCell::new(0));
|
||||
|
||||
pub fn gen_unique_edge_ids<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
state: Option<&mut S>,
|
||||
src: 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 {
|
||||
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 {
|
||||
EDGES_MAP[id as usize] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_hashed_edge_ids<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
src: 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))
|
||||
}
|
||||
|
||||
pub extern "C" fn trace_edge_hitcount_ptr(id: u64, _data: u64) {
|
||||
pub extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) {
|
||||
unsafe {
|
||||
let ptr = EDGES_MAP_PTR.add(id as usize);
|
||||
*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 {
|
||||
let ptr = EDGES_MAP_PTR.add(id as usize);
|
||||
*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>(
|
||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
) -> Option<u64>
|
||||
@ -362,7 +365,7 @@ where
|
||||
*/
|
||||
|
||||
pub fn gen_hashed_block_ids<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
) -> Option<u64>
|
||||
@ -383,7 +386,7 @@ where
|
||||
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 {
|
||||
PREV_LOC.with(|prev_loc| {
|
||||
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 {
|
||||
PREV_LOC.with(|prev_loc| {
|
||||
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_PTR_NUM - 1);
|
||||
|
@ -14,11 +14,7 @@ use std::{
|
||||
ffi::{CStr, CString},
|
||||
ptr::null_mut,
|
||||
};
|
||||
use std::{
|
||||
slice::from_raw_parts,
|
||||
str::from_utf8_unchecked,
|
||||
sync::{Mutex, OnceLock},
|
||||
};
|
||||
use std::{slice::from_raw_parts, str::from_utf8_unchecked};
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
use libc::c_int;
|
||||
@ -224,11 +220,12 @@ pub enum VerifyAccess {
|
||||
Write = libc::PROT_READ | libc::PROT_WRITE,
|
||||
}
|
||||
|
||||
// syshook_ret
|
||||
#[repr(C)]
|
||||
#[cfg_attr(feature = "python", pyclass)]
|
||||
#[cfg_attr(feature = "python", derive(FromPyObject))]
|
||||
pub struct SyscallHookResult {
|
||||
pub retval: u64,
|
||||
pub retval: GuestAddr,
|
||||
pub skip_syscall: bool,
|
||||
}
|
||||
|
||||
@ -237,7 +234,7 @@ pub struct SyscallHookResult {
|
||||
impl SyscallHookResult {
|
||||
#[new]
|
||||
#[must_use]
|
||||
pub fn new(value: Option<u64>) -> Self {
|
||||
pub fn new(value: Option<GuestAddr>) -> Self {
|
||||
value.map_or(
|
||||
Self {
|
||||
retval: 0,
|
||||
@ -254,7 +251,7 @@ impl SyscallHookResult {
|
||||
#[cfg(not(feature = "python"))]
|
||||
impl SyscallHookResult {
|
||||
#[must_use]
|
||||
pub fn new(value: Option<u64>) -> Self {
|
||||
pub fn new(value: Option<GuestAddr>) -> Self {
|
||||
value.map_or(
|
||||
Self {
|
||||
retval: 0,
|
||||
@ -340,13 +337,6 @@ extern "C" {
|
||||
static guest_base: usize;
|
||||
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_force_dfl: i32;
|
||||
}
|
||||
@ -370,6 +360,7 @@ extern "C" fn qemu_cleanup_atexit() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO rely completely on libafl_qemu_sys
|
||||
extern "C" {
|
||||
//static libafl_page_size: GuestUsize;
|
||||
fn libafl_page_from_addr(addr: GuestAddr) -> GuestAddr;
|
||||
@ -395,87 +386,10 @@ extern "C" {
|
||||
fn libafl_flush_jit();
|
||||
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;
|
||||
|
||||
// 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(
|
||||
callback: extern "C" fn(*const u8, usize, *const ()) -> i32,
|
||||
callback: extern "C" fn(*const (), *const u8, usize) -> i32,
|
||||
data: *const (),
|
||||
);
|
||||
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![];
|
||||
|
||||
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 {
|
||||
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));
|
||||
@ -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)]
|
||||
pub struct Emulator {
|
||||
_private: (),
|
||||
use std::pin::Pin;
|
||||
|
||||
#[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)]
|
||||
@ -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)]
|
||||
impl Emulator {
|
||||
#[allow(clippy::must_use_candidate, clippy::similar_names)]
|
||||
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() {
|
||||
return Err(EmuError::EmptyArgs);
|
||||
}
|
||||
@ -961,6 +934,14 @@ impl Emulator {
|
||||
if i32::try_from(argc).is_err() {
|
||||
return Err(EmuError::TooManyArgs(argc));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
if EMULATOR_IS_INITIALIZED {
|
||||
return Err(EmuError::MultipleInstances);
|
||||
}
|
||||
EMULATOR_IS_INITIALIZED = true;
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
let argc = argc as i32;
|
||||
|
||||
@ -985,11 +966,21 @@ impl Emulator {
|
||||
libc::atexit(qemu_cleanup_atexit);
|
||||
libafl_qemu_sys::syx_snapshot_init();
|
||||
}
|
||||
*is_initialized = true;
|
||||
}
|
||||
Ok(Emulator { _private: () })
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get() -> Option<Self> {
|
||||
unsafe {
|
||||
if EMULATOR_IS_INITIALIZED {
|
||||
Some(Self::new_empty())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn new_empty() -> Emulator {
|
||||
Emulator { _private: () }
|
||||
@ -1141,22 +1132,6 @@ impl Emulator {
|
||||
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.
|
||||
/// # 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,
|
||||
gen: Option<extern "C" fn(GuestAddr, GuestAddr, u64) -> u64>,
|
||||
exec: Option<extern "C" fn(u64, u64)>,
|
||||
data: u64,
|
||||
) {
|
||||
unsafe { libafl_add_edge_hook(gen, exec, data) }
|
||||
data: T,
|
||||
addr: GuestAddr,
|
||||
callback: extern "C" fn(T, GuestAddr),
|
||||
invalidate_block: bool,
|
||||
) -> 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(
|
||||
&self,
|
||||
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,
|
||||
) {
|
||||
unsafe { libafl_add_block_hook(gen, post_gen, exec, data) }
|
||||
#[must_use]
|
||||
pub fn remove_hook(&self, id: HookId, invalidate_block: bool) -> bool {
|
||||
unsafe { libafl_qemu_sys::libafl_qemu_remove_hook(id.0, i32::from(invalidate_block)) != 0 }
|
||||
}
|
||||
|
||||
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,
|
||||
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,
|
||||
) {
|
||||
unsafe { libafl_add_read_hook(gen, exec1, exec2, exec4, exec8, exec_n, data) }
|
||||
data: T,
|
||||
gen: Option<extern "C" fn(T, GuestAddr, GuestAddr) -> u64>,
|
||||
exec: Option<extern "C" fn(T, u64)>,
|
||||
) -> HookId {
|
||||
unsafe {
|
||||
let data: u64 = data.into().0;
|
||||
let gen: Option<extern "C" fn(u64, GuestAddr, GuestAddr) -> u64> =
|
||||
core::mem::transmute(gen);
|
||||
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
|
||||
pub fn add_write_hooks(
|
||||
pub fn add_write_hooks<T: Into<HookData>>(
|
||||
&self,
|
||||
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,
|
||||
) {
|
||||
unsafe { libafl_add_write_hook(gen, exec1, exec2, exec4, exec8, exec_n, data) }
|
||||
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_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,
|
||||
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,
|
||||
) {
|
||||
unsafe { libafl_add_cmp_hook(gen, exec1, exec2, exec4, exec8, data) }
|
||||
data: T,
|
||||
gen: Option<extern "C" fn(T, GuestAddr, usize) -> u64>,
|
||||
exec1: Option<extern "C" fn(T, u64, u8, u8)>,
|
||||
exec2: Option<extern "C" fn(T, u64, u16, u16)>,
|
||||
exec4: Option<extern "C" fn(T, u64, u32, u32)>,
|
||||
exec8: Option<extern "C" fn(T, u64, u64, u64)>,
|
||||
) -> HookId {
|
||||
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) {
|
||||
unsafe { libafl_add_backdoor_hook(exec, data) };
|
||||
pub fn add_backdoor_hook<T: Into<HookData>>(
|
||||
&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")]
|
||||
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 {
|
||||
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)]
|
||||
pub fn add_gdb_cmd(&self, callback: Box<dyn FnMut(&Self, &str) -> bool>) {
|
||||
unsafe {
|
||||
@ -1519,6 +1652,7 @@ pub mod pybind {
|
||||
static mut PY_GENERIC_HOOKS: Vec<(GuestAddr, PyObject)> = vec![];
|
||||
|
||||
extern "C" fn py_syscall_hook_wrapper(
|
||||
data: u64,
|
||||
sys_num: i32,
|
||||
a0: 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 };
|
||||
Python::with_gil(|py| {
|
||||
obj.call0(py).expect("Error in the hook");
|
||||
@ -1678,7 +1812,7 @@ pub mod pybind {
|
||||
unsafe {
|
||||
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) {
|
||||
@ -1686,15 +1820,15 @@ pub mod pybind {
|
||||
let idx = PY_GENERIC_HOOKS.len();
|
||||
PY_GENERIC_HOOKS.push((addr, hook));
|
||||
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 {
|
||||
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>,
|
||||
{
|
||||
inner: InProcessExecutor<'a, H, OT, S>,
|
||||
hooks: &'a mut QemuHooks<'a, QT, S>,
|
||||
hooks: &'a mut QemuHooks<QT, S>,
|
||||
first_exec: bool,
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ where
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
pub fn new<EM, OF, Z>(
|
||||
hooks: &'a mut QemuHooks<'a, QT, S>,
|
||||
hooks: &'a mut QemuHooks<QT, S>,
|
||||
harness_fn: &'a mut H,
|
||||
observers: OT,
|
||||
fuzzer: &mut Z,
|
||||
@ -186,11 +186,11 @@ where
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn hooks(&self) -> &QemuHooks<'a, QT, S> {
|
||||
pub fn hooks(&self) -> &QemuHooks<QT, S> {
|
||||
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
|
||||
}
|
||||
|
||||
@ -280,7 +280,7 @@ where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
first_exec: bool,
|
||||
hooks: &'a mut QemuHooks<'a, QT, S>,
|
||||
hooks: &'a mut QemuHooks<QT, S>,
|
||||
inner: InProcessForkExecutor<'a, H, OT, S, SP>,
|
||||
}
|
||||
|
||||
@ -311,7 +311,7 @@ where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
pub fn new<EM, OF, Z>(
|
||||
hooks: &'a mut QemuHooks<'a, QT, S>,
|
||||
hooks: &'a mut QemuHooks<QT, S>,
|
||||
harness_fn: &'a mut H,
|
||||
observers: OT,
|
||||
fuzzer: &mut Z,
|
||||
@ -349,11 +349,11 @@ where
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn hooks(&self) -> &QemuHooks<'a, QT, S> {
|
||||
pub fn hooks(&self) -> &QemuHooks<QT, S> {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -16,13 +16,13 @@ where
|
||||
{
|
||||
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
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
}
|
||||
|
||||
fn first_exec<QT>(&self, _hooks: &QemuHooks<'_, QT, S>)
|
||||
fn first_exec<QT>(&self, _hooks: &QemuHooks<QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
@ -48,11 +48,11 @@ where
|
||||
{
|
||||
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
|
||||
QT: QemuHelperTuple<S>;
|
||||
|
||||
fn first_exec_all<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
||||
fn first_exec_all<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<S>;
|
||||
|
||||
@ -74,13 +74,13 @@ where
|
||||
{
|
||||
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
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
}
|
||||
|
||||
fn first_exec_all<QT>(&self, _hooks: &QemuHooks<'_, QT, S>)
|
||||
fn first_exec_all<QT>(&self, _hooks: &QemuHooks<QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
@ -108,7 +108,7 @@ where
|
||||
{
|
||||
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
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
@ -116,7 +116,7 @@ where
|
||||
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
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@ use crate::SYS_newfstatat;
|
||||
use crate::{
|
||||
emu::{Emulator, MmapPerms, SyscallHookResult},
|
||||
helper::{QemuHelper, QemuHelperTuple},
|
||||
hooks::QemuHooks,
|
||||
hooks::{Hook, QemuHooks},
|
||||
GuestAddr, SYS_fstat, SYS_fstatfs, SYS_futex, SYS_getrandom, SYS_mprotect, SYS_mremap,
|
||||
SYS_munmap, SYS_pread64, SYS_read, SYS_readlinkat, SYS_statfs,
|
||||
};
|
||||
@ -487,23 +487,23 @@ impl<S> QemuHelper<S> for QemuSnapshotHelper
|
||||
where
|
||||
S: UsesInput + HasMetadata,
|
||||
{
|
||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
||||
fn first_exec<QT>(&self, hooks: &QemuHooks<QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
hooks.writes(
|
||||
None,
|
||||
Some(trace_write1_snapshot::<QT, S>),
|
||||
Some(trace_write2_snapshot::<QT, S>),
|
||||
Some(trace_write4_snapshot::<QT, S>),
|
||||
Some(trace_write8_snapshot::<QT, S>),
|
||||
Some(trace_write_n_snapshot::<QT, S>),
|
||||
Hook::Empty,
|
||||
Hook::Function(trace_write1_snapshot::<QT, S>),
|
||||
Hook::Function(trace_write2_snapshot::<QT, S>),
|
||||
Hook::Function(trace_write4_snapshot::<QT, S>),
|
||||
Hook::Function(trace_write8_snapshot::<QT, S>),
|
||||
Hook::Function(trace_write_n_snapshot::<QT, S>),
|
||||
);
|
||||
|
||||
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) {
|
||||
@ -516,7 +516,7 @@ where
|
||||
}
|
||||
|
||||
pub fn trace_write1_snapshot<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -529,7 +529,7 @@ pub fn trace_write1_snapshot<QT, S>(
|
||||
}
|
||||
|
||||
pub fn trace_write2_snapshot<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -542,7 +542,7 @@ pub fn trace_write2_snapshot<QT, S>(
|
||||
}
|
||||
|
||||
pub fn trace_write4_snapshot<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -555,7 +555,7 @@ pub fn trace_write4_snapshot<QT, S>(
|
||||
}
|
||||
|
||||
pub fn trace_write8_snapshot<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -568,7 +568,7 @@ pub fn trace_write8_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>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
@ -584,17 +584,17 @@ pub fn trace_write_n_snapshot<QT, S>(
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub fn filter_mmap_snapshot<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
sys_num: i32,
|
||||
a0: u64,
|
||||
a1: u64,
|
||||
_a2: u64,
|
||||
_a3: u64,
|
||||
_a4: u64,
|
||||
_a5: u64,
|
||||
_a6: u64,
|
||||
_a7: u64,
|
||||
a0: GuestAddr,
|
||||
a1: GuestAddr,
|
||||
_a2: GuestAddr,
|
||||
_a3: GuestAddr,
|
||||
_a4: GuestAddr,
|
||||
_a5: GuestAddr,
|
||||
_a6: GuestAddr,
|
||||
_a7: GuestAddr,
|
||||
) -> SyscallHookResult
|
||||
where
|
||||
S: UsesInput,
|
||||
@ -612,19 +612,19 @@ where
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub fn trace_mmap_snapshot<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
result: u64,
|
||||
result: GuestAddr,
|
||||
sys_num: i32,
|
||||
a0: u64,
|
||||
a1: u64,
|
||||
a2: u64,
|
||||
a3: u64,
|
||||
_a4: u64,
|
||||
_a5: u64,
|
||||
_a6: u64,
|
||||
_a7: u64,
|
||||
) -> u64
|
||||
a0: GuestAddr,
|
||||
a1: GuestAddr,
|
||||
a2: GuestAddr,
|
||||
a3: GuestAddr,
|
||||
_a4: GuestAddr,
|
||||
_a5: GuestAddr,
|
||||
_a6: GuestAddr,
|
||||
_a7: GuestAddr,
|
||||
) -> GuestAddr
|
||||
where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
@ -633,15 +633,15 @@ where
|
||||
match i64::from(sys_num) {
|
||||
SYS_read | SYS_pread64 => {
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(a1 as GuestAddr, a2 as usize);
|
||||
h.access(a1, a2 as usize);
|
||||
}
|
||||
SYS_readlinkat => {
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(a2 as GuestAddr, a3 as usize);
|
||||
h.access(a2, a3 as usize);
|
||||
}
|
||||
SYS_futex => {
|
||||
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(
|
||||
cpu_target = "arm",
|
||||
@ -652,27 +652,27 @@ where
|
||||
SYS_newfstatat => {
|
||||
if a2 != 0 {
|
||||
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"))]
|
||||
SYS_fstatat64 => {
|
||||
if a2 != 0 {
|
||||
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 => {
|
||||
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 => {
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
h.access(a0 as GuestAddr, a1 as usize);
|
||||
h.access(a0, a1 as usize);
|
||||
}
|
||||
// mmap syscalls
|
||||
sys_const => {
|
||||
if result as GuestAddr == GuestAddr::MAX
|
||||
if result == GuestAddr::MAX
|
||||
/* -1 */
|
||||
{
|
||||
return result;
|
||||
@ -684,7 +684,7 @@ where
|
||||
if sys_const == SYS_mmap2 {
|
||||
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||
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 let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||
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 {
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
// TODO get the old permissions from the removed mapping
|
||||
h.remove_mapped(a0 as GuestAddr, a1 as usize);
|
||||
h.add_mapped(result as GuestAddr, a2 as usize, None);
|
||||
h.remove_mapped(a0, a1 as usize);
|
||||
h.add_mapped(result, a2 as usize, None);
|
||||
} else if sys_const == SYS_mprotect {
|
||||
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
|
||||
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 {
|
||||
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
|
||||
if !h.accurate_unmap && !h.is_unmap_allowed(a0 as GuestAddr, a1 as usize) {
|
||||
h.remove_mapped(a0 as GuestAddr, a1 as usize);
|
||||
if !h.accurate_unmap && !h.is_unmap_allowed(a0, a1 as usize) {
|
||||
h.remove_mapped(a0, a1 as usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ where
|
||||
|
||||
if self.use_cmplog.unwrap_or(false) {
|
||||
let mut hooks = QemuHooks::new(
|
||||
emulator,
|
||||
emulator.clone(),
|
||||
#[cfg(not(any(feature = "mips", feature = "hexagon")))]
|
||||
tuple_list!(
|
||||
QemuEdgeCoverageHelper::default(),
|
||||
@ -325,8 +325,10 @@ where
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let mut hooks =
|
||||
QemuHooks::new(emulator, tuple_list!(QemuEdgeCoverageHelper::default()));
|
||||
let mut hooks = QemuHooks::new(
|
||||
emulator.clone(),
|
||||
tuple_list!(QemuEdgeCoverageHelper::default()),
|
||||
);
|
||||
|
||||
let executor = QemuExecutor::new(
|
||||
&mut hooks,
|
||||
|
Loading…
x
Reference in New Issue
Block a user