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

View File

@ -3,7 +3,7 @@ use which::which;
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
const QEMU_REVISION: &str = "35dcfc0c115da262622fdc811d089155f26a2abe";
const QEMU_REVISION: &str = "17c1f083eefca42088d6a88df04c65713f1cc58a";
fn build_dep_check(tools: &[&str]) {
for tool in tools {

View File

@ -188,6 +188,7 @@ extern "C" {
fn libafl_qemu_num_regs() -> i32;
fn libafl_qemu_set_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_remove_hook(addr: u64) -> 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
pub fn set_exec_edge_hook(&self, hook: extern "C" fn(id: u64)) {
@ -814,6 +821,10 @@ pub mod pybind {
self.emu.load_addr()
}
fn flush_jit(&self) {
self.emu.flush_jit();
}
fn map_private(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult<GuestAddr> {
if let Ok(p) = MmapPerms::try_from(perms) {
self.emu

View File

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

View File

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

View File

@ -12,10 +12,12 @@ use crate::{
emu::{Emulator, MmapPerms},
helper::{QemuHelper, QemuHelperTuple},
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_MASK: GuestAddr = !(SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
#[derive(Debug)]
pub struct SnapshotPageInfo {
@ -106,9 +108,9 @@ impl QemuSnapshotHelper {
pub fn access(&mut self, addr: GuestAddr, size: usize) {
debug_assert!(size > 0);
let page = addr & (SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
let page = addr & SNAPSHOT_PAGE_MASK;
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 {
self.page_access(second_page);
}
@ -116,6 +118,7 @@ impl QemuSnapshotHelper {
pub fn reset(&mut self, emulator: &Emulator) {
self.reset_maps(emulator);
for acc in self.accesses.iter_mut() {
for page in unsafe { &(*acc.get()).dirty } {
if let Some(info) = self.pages.get_mut(page) {
@ -127,6 +130,7 @@ impl QemuSnapshotHelper {
}
unsafe { (*acc.get()).clear() };
}
emulator.set_brk(self.brk);
}
@ -146,7 +150,7 @@ impl QemuSnapshotHelper {
let addr = r.interval().start;
let end = r.interval().end;
let perms = r.data();
let mut page = addr & (SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
let mut page = addr & SNAPSHOT_PAGE_MASK;
let mut prev = None;
while page < end {
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(non_upper_case_globals)]
pub fn trace_mmap_snapshot<I, QT, S>(
_emulator: &Emulator,
helpers: &mut QT,
@ -298,7 +303,7 @@ pub fn trace_mmap_snapshot<I, QT, S>(
a0: u64,
a1: u64,
a2: u64,
_a3: u64,
a3: u64,
_a4: u64,
_a5: u64,
_a6: u64,
@ -308,29 +313,61 @@ where
I: Input,
QT: QemuHelperTuple<I, S>,
{
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) {
// NOT A COMPLETE LIST OF MEMORY EFFECTS
match i64::from(sys_num) {
SYS_read => {
let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>()
.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 {
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) {
SYS_readlinkat => {
let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>()
.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