Fix snapshots in libafl_qemu (#556)

* afl_exec_sec feature, disabled by default

* Fix snapshots in libafl_qemu

* working memory snapshots
This commit is contained in:
Andrea Fioraldi 2022-02-28 21:23:20 +01:00 committed by GitHub
parent c4fb92a1a4
commit bf9d2b4c57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 78 additions and 28 deletions

View File

@ -591,12 +591,12 @@ where
executor.observers_mut().pre_exec_all(state, input)?; executor.observers_mut().pre_exec_all(state, input)?;
mark_feature_time!(state, PerfFeature::PreExecObservers); mark_feature_time!(state, PerfFeature::PreExecObservers);
*state.executions_mut() += 1;
start_timer!(state); start_timer!(state);
let exit_kind = executor.run_target(self, state, event_mgr, input)?; let exit_kind = executor.run_target(self, state, event_mgr, input)?;
mark_feature_time!(state, PerfFeature::TargetExecution); mark_feature_time!(state, PerfFeature::TargetExecution);
*state.executions_mut() += 1;
start_timer!(state); start_timer!(state);
executor executor
.observers_mut() .observers_mut()
@ -651,12 +651,12 @@ where
executor.observers_mut().pre_exec_all(state, input)?; executor.observers_mut().pre_exec_all(state, input)?;
mark_feature_time!(state, PerfFeature::PreExecObservers); mark_feature_time!(state, PerfFeature::PreExecObservers);
*state.executions_mut() += 1;
start_timer!(state); start_timer!(state);
let exit_kind = executor.run_target(self, state, event_mgr, input)?; let exit_kind = executor.run_target(self, state, event_mgr, input)?;
mark_feature_time!(state, PerfFeature::TargetExecution); mark_feature_time!(state, PerfFeature::TargetExecution);
*state.executions_mut() += 1;
start_timer!(state); start_timer!(state);
executor executor
.observers_mut() .observers_mut()

View File

@ -3,7 +3,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 = "35dcfc0c115da262622fdc811d089155f26a2abe"; const QEMU_REVISION: &str = "17c1f083eefca42088d6a88df04c65713f1cc58a";
fn build_dep_check(tools: &[&str]) { fn build_dep_check(tools: &[&str]) {
for tool in tools { for tool in tools {

View File

@ -188,6 +188,7 @@ extern "C" {
fn libafl_qemu_num_regs() -> i32; fn libafl_qemu_num_regs() -> i32;
fn libafl_qemu_set_breakpoint(addr: u64) -> i32; fn libafl_qemu_set_breakpoint(addr: u64) -> i32;
fn libafl_qemu_remove_breakpoint(addr: u64) -> i32; fn libafl_qemu_remove_breakpoint(addr: u64) -> i32;
fn libafl_flush_jit();
fn libafl_qemu_set_hook(addr: u64, callback: extern "C" fn(u64), val: u64) -> i32; fn libafl_qemu_set_hook(addr: u64, callback: extern "C" fn(u64), val: u64) -> i32;
fn libafl_qemu_remove_hook(addr: u64) -> i32; fn libafl_qemu_remove_hook(addr: u64) -> i32;
fn libafl_qemu_run() -> i32; fn libafl_qemu_run() -> i32;
@ -535,6 +536,12 @@ impl Emulator {
} }
} }
pub fn flush_jit(&self) {
unsafe {
libafl_flush_jit();
}
}
// TODO add has_X_hook() and panic when setting a hook for the second time // TODO add has_X_hook() and panic when setting a hook for the second time
pub fn set_exec_edge_hook(&self, hook: extern "C" fn(id: u64)) { pub fn set_exec_edge_hook(&self, hook: extern "C" fn(id: u64)) {
@ -814,6 +821,10 @@ pub mod pybind {
self.emu.load_addr() self.emu.load_addr()
} }
fn flush_jit(&self) {
self.emu.flush_jit();
}
fn map_private(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult<GuestAddr> { fn map_private(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult<GuestAddr> {
if let Ok(p) = MmapPerms::try_from(perms) { if let Ok(p) = MmapPerms::try_from(perms) {
self.emu self.emu

View File

@ -1104,6 +1104,8 @@ where
); );
HOOKS_IS_INITIALIZED = true; HOOKS_IS_INITIALIZED = true;
} }
// re-translate blocks with hooks
emulator.flush_jit();
let slf = Box::pin(Self { let slf = Box::pin(Self {
emulator, emulator,
helpers, helpers,

View File

@ -10,6 +10,8 @@
use std::env; use std::env;
pub use strum::IntoEnumIterator;
#[cfg(cpu_target = "aarch64")] #[cfg(cpu_target = "aarch64")]
pub mod aarch64; pub mod aarch64;
#[cfg(all(cpu_target = "aarch64", not(feature = "clippy")))] #[cfg(all(cpu_target = "aarch64", not(feature = "clippy")))]
@ -77,8 +79,6 @@ use pyo3::prelude::*;
#[pyo3(name = "libafl_qemu")] #[pyo3(name = "libafl_qemu")]
#[allow(clippy::items_after_statements, clippy::too_many_lines)] #[allow(clippy::items_after_statements, clippy::too_many_lines)]
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
use strum::IntoEnumIterator;
let regsm = PyModule::new(py, "regs")?; let regsm = PyModule::new(py, "regs")?;
for r in Regs::iter() { for r in Regs::iter() {
let v: i32 = r.into(); let v: i32 = r.into();

View File

@ -12,10 +12,12 @@ use crate::{
emu::{Emulator, MmapPerms}, emu::{Emulator, MmapPerms},
helper::{QemuHelper, QemuHelperTuple}, helper::{QemuHelper, QemuHelperTuple},
hooks::QemuHooks, hooks::QemuHooks,
GuestAddr, SYS_mmap, SYS_mprotect, SYS_mremap, GuestAddr, SYS_getrandom, SYS_mmap, SYS_mprotect, SYS_mremap, SYS_newfstatat, SYS_read,
SYS_readlinkat,
}; };
pub const SNAPSHOT_PAGE_SIZE: usize = 4096; pub const SNAPSHOT_PAGE_SIZE: usize = 4096;
pub const SNAPSHOT_PAGE_MASK: GuestAddr = !(SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
#[derive(Debug)] #[derive(Debug)]
pub struct SnapshotPageInfo { pub struct SnapshotPageInfo {
@ -106,9 +108,9 @@ impl QemuSnapshotHelper {
pub fn access(&mut self, addr: GuestAddr, size: usize) { pub fn access(&mut self, addr: GuestAddr, size: usize) {
debug_assert!(size > 0); debug_assert!(size > 0);
let page = addr & (SNAPSHOT_PAGE_SIZE as GuestAddr - 1); let page = addr & SNAPSHOT_PAGE_MASK;
self.page_access(page); self.page_access(page);
let second_page = (addr + size as GuestAddr - 1) & (SNAPSHOT_PAGE_SIZE as GuestAddr - 1); let second_page = (addr + size as GuestAddr - 1) & SNAPSHOT_PAGE_MASK;
if page != second_page { if page != second_page {
self.page_access(second_page); self.page_access(second_page);
} }
@ -116,6 +118,7 @@ impl QemuSnapshotHelper {
pub fn reset(&mut self, emulator: &Emulator) { pub fn reset(&mut self, emulator: &Emulator) {
self.reset_maps(emulator); self.reset_maps(emulator);
for acc in self.accesses.iter_mut() { for acc in self.accesses.iter_mut() {
for page in unsafe { &(*acc.get()).dirty } { for page in unsafe { &(*acc.get()).dirty } {
if let Some(info) = self.pages.get_mut(page) { if let Some(info) = self.pages.get_mut(page) {
@ -127,6 +130,7 @@ impl QemuSnapshotHelper {
} }
unsafe { (*acc.get()).clear() }; unsafe { (*acc.get()).clear() };
} }
emulator.set_brk(self.brk); emulator.set_brk(self.brk);
} }
@ -146,7 +150,7 @@ impl QemuSnapshotHelper {
let addr = r.interval().start; let addr = r.interval().start;
let end = r.interval().end; let end = r.interval().end;
let perms = r.data(); let perms = r.data();
let mut page = addr & (SNAPSHOT_PAGE_SIZE as GuestAddr - 1); let mut page = addr & SNAPSHOT_PAGE_MASK;
let mut prev = None; let mut prev = None;
while page < end { while page < end {
if let Some(info) = self.pages.get(&page) { if let Some(info) = self.pages.get(&page) {
@ -289,6 +293,7 @@ pub fn trace_write_n_snapshot<I, QT, S>(
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[allow(non_upper_case_globals)]
pub fn trace_mmap_snapshot<I, QT, S>( pub fn trace_mmap_snapshot<I, QT, S>(
_emulator: &Emulator, _emulator: &Emulator,
helpers: &mut QT, helpers: &mut QT,
@ -298,7 +303,7 @@ pub fn trace_mmap_snapshot<I, QT, S>(
a0: u64, a0: u64,
a1: u64, a1: u64,
a2: u64, a2: u64,
_a3: u64, a3: u64,
_a4: u64, _a4: u64,
_a5: u64, _a5: u64,
_a6: u64, _a6: u64,
@ -308,29 +313,61 @@ where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
if result as GuestAddr == GuestAddr::MAX // NOT A COMPLETE LIST OF MEMORY EFFECTS
/* -1 */ match i64::from(sys_num) {
{ SYS_read => {
return result;
}
if i64::from(sys_num) == SYS_mmap {
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
let h = helpers let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>() .match_first_type_mut::<QemuSnapshotHelper>()
.unwrap(); .unwrap();
h.add_mapped(result as GuestAddr, a1 as usize, Some(prot)); h.access(a1 as GuestAddr, a2 as usize);
} }
} else if i64::from(sys_num) == SYS_mremap { SYS_readlinkat => {
let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.add_mapped(result as GuestAddr, a2 as usize, None);
} else if i64::from(sys_num) == SYS_mprotect {
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
let h = helpers let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>() .match_first_type_mut::<QemuSnapshotHelper>()
.unwrap(); .unwrap();
h.add_mapped(a0 as GuestAddr, a2 as usize, Some(prot)); h.access(a2 as GuestAddr, a3 as usize);
}
SYS_newfstatat => {
if a2 != 0 {
let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(a2 as GuestAddr, 4096); // stat is not greater than a page
}
}
SYS_getrandom => {
let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.access(a0 as GuestAddr, a1 as usize);
}
// mmap syscalls
_ => {
if result as GuestAddr == GuestAddr::MAX
/* -1 */
{
return result;
}
if i64::from(sys_num) == SYS_mmap {
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.add_mapped(result as GuestAddr, a1 as usize, Some(prot));
}
} else if i64::from(sys_num) == SYS_mremap {
let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.add_mapped(result as GuestAddr, a2 as usize, None);
} else if i64::from(sys_num) == SYS_mprotect {
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.add_mapped(a0 as GuestAddr, a2 as usize, Some(prot));
}
}
} }
} }
result result