QEMU filtering rework + paging filtering (#1705)
* Added paging filtering. Reworked address range filtering to fit with new generic code. * Fix: renamed remaining QemuInstrumentationFilter instances. * Fix: clippy + format * Updated qemu-libafl-bridge * Fix QEMU userspace crash handler (#1706) * Fix QEMU userspace crash handler * no_std * libafl_cc custom llvm_config lookup for solaris/illumos (#1708) * fix simd (#1709) * Updated qemu --------- Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com> Co-authored-by: David CARLIER <devnexen@gmail.com> Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
This commit is contained in:
parent
ea61b79012
commit
830faec95f
@ -28,7 +28,7 @@ use libafl_bolts::{
|
||||
};
|
||||
use libafl_qemu::{
|
||||
drcov::QemuDrCovHelper, elf::EasyElf, emu::Emulator, ArchExtras, CallingConvention, GuestAddr,
|
||||
GuestReg, MmapPerms, QemuExecutor, QemuHooks, QemuInstrumentationFilter, Regs,
|
||||
GuestReg, MmapPerms, QemuExecutor, QemuHooks, QemuInstrumentationAddressRangeFilter, Regs,
|
||||
};
|
||||
use rangemap::RangeMap;
|
||||
|
||||
@ -238,7 +238,7 @@ pub fn fuzz() {
|
||||
let mut hooks = QemuHooks::new(
|
||||
emu.clone(),
|
||||
tuple_list!(QemuDrCovHelper::new(
|
||||
QemuInstrumentationFilter::None,
|
||||
QemuInstrumentationAddressRangeFilter::None,
|
||||
rangemap,
|
||||
PathBuf::from(coverage),
|
||||
false,
|
||||
|
@ -15,7 +15,7 @@ use libafl_qemu::{
|
||||
cmplog::QemuCmpLogHelper,
|
||||
edges::QemuEdgeCoverageHelper,
|
||||
elf::EasyElf,
|
||||
ArchExtras, Emulator, GuestAddr, QemuInstrumentationFilter,
|
||||
ArchExtras, Emulator, GuestAddr, QemuInstrumentationAddressRangeFilter,
|
||||
};
|
||||
|
||||
use crate::{instance::Instance, options::FuzzerOptions};
|
||||
@ -59,7 +59,10 @@ impl<'a> Client<'a> {
|
||||
Ok(start_pc)
|
||||
}
|
||||
|
||||
fn coverage_filter(&self, emu: &Emulator) -> Result<QemuInstrumentationFilter, Error> {
|
||||
fn coverage_filter(
|
||||
&self,
|
||||
emu: &Emulator,
|
||||
) -> Result<QemuInstrumentationAddressRangeFilter, Error> {
|
||||
/* Conversion is required on 32-bit targets, but not on 64-bit ones */
|
||||
if let Some(includes) = &self.options.include {
|
||||
#[cfg_attr(target_pointer_width = "64", allow(clippy::useless_conversion))]
|
||||
@ -70,7 +73,7 @@ impl<'a> Client<'a> {
|
||||
end: x.end.into(),
|
||||
})
|
||||
.collect::<Vec<Range<GuestAddr>>>();
|
||||
Ok(QemuInstrumentationFilter::AllowList(rules))
|
||||
Ok(QemuInstrumentationAddressRangeFilter::AllowList(rules))
|
||||
} else if let Some(excludes) = &self.options.exclude {
|
||||
#[cfg_attr(target_pointer_width = "64", allow(clippy::useless_conversion))]
|
||||
let rules = excludes
|
||||
@ -80,14 +83,16 @@ impl<'a> Client<'a> {
|
||||
end: x.end.into(),
|
||||
})
|
||||
.collect::<Vec<Range<GuestAddr>>>();
|
||||
Ok(QemuInstrumentationFilter::DenyList(rules))
|
||||
Ok(QemuInstrumentationAddressRangeFilter::DenyList(rules))
|
||||
} else {
|
||||
let mut elf_buffer = Vec::new();
|
||||
let elf = EasyElf::from_file(emu.binary_path(), &mut elf_buffer)?;
|
||||
let range = elf
|
||||
.get_section(".text", emu.load_addr())
|
||||
.ok_or_else(|| Error::key_not_found("Failed to find .text section"))?;
|
||||
Ok(QemuInstrumentationFilter::AllowList(vec![range]))
|
||||
Ok(QemuInstrumentationAddressRangeFilter::AllowList(vec![
|
||||
range,
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 = "32206d23c33a55c9e519e4ae67038ab27d713a24";
|
||||
const QEMU_REVISION: &str = "c92d7c2ef66811278e8d665d4aec57661c980186";
|
||||
|
||||
fn build_dep_check(tools: &[&str]) {
|
||||
for tool in tools {
|
||||
|
@ -21,7 +21,10 @@ use rangemap::RangeMap;
|
||||
use crate::{
|
||||
calls::FullBacktraceCollector,
|
||||
emu::{EmuError, Emulator, MemAccessInfo, SyscallHookResult},
|
||||
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
helper::{
|
||||
HasInstrumentationFilter, IsFilter, QemuHelper, QemuHelperTuple,
|
||||
QemuInstrumentationAddressRangeFilter,
|
||||
},
|
||||
hooks::{Hook, QemuHooks},
|
||||
snapshot::QemuSnapshotHelper,
|
||||
GuestAddr, Regs,
|
||||
@ -734,7 +737,7 @@ pub struct QemuAsanHelper {
|
||||
detect_leaks: bool,
|
||||
empty: bool,
|
||||
rt: Pin<Box<AsanGiovese>>,
|
||||
filter: QemuInstrumentationFilter,
|
||||
filter: QemuInstrumentationAddressRangeFilter,
|
||||
}
|
||||
|
||||
impl QemuAsanHelper {
|
||||
@ -742,7 +745,7 @@ impl QemuAsanHelper {
|
||||
pub fn default(rt: Pin<Box<AsanGiovese>>) -> Self {
|
||||
Self::new(
|
||||
rt,
|
||||
QemuInstrumentationFilter::None,
|
||||
QemuInstrumentationAddressRangeFilter::None,
|
||||
QemuAsanOptions::Snapshot,
|
||||
)
|
||||
}
|
||||
@ -750,7 +753,7 @@ impl QemuAsanHelper {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
mut rt: Pin<Box<AsanGiovese>>,
|
||||
filter: QemuInstrumentationFilter,
|
||||
filter: QemuInstrumentationAddressRangeFilter,
|
||||
options: QemuAsanOptions,
|
||||
) -> Self {
|
||||
assert!(unsafe { ASAN_INITED }, "The ASan runtime is not initialized, use init_with_asan(...) instead of just Emulator::new(...)");
|
||||
@ -773,7 +776,7 @@ impl QemuAsanHelper {
|
||||
#[must_use]
|
||||
pub fn with_error_callback(
|
||||
mut rt: Pin<Box<AsanGiovese>>,
|
||||
filter: QemuInstrumentationFilter,
|
||||
filter: QemuInstrumentationAddressRangeFilter,
|
||||
error_callback: AsanErrorCallback,
|
||||
options: QemuAsanOptions,
|
||||
) -> Self {
|
||||
@ -798,7 +801,7 @@ impl QemuAsanHelper {
|
||||
#[must_use]
|
||||
pub fn with_asan_report(
|
||||
rt: Pin<Box<AsanGiovese>>,
|
||||
filter: QemuInstrumentationFilter,
|
||||
filter: QemuInstrumentationAddressRangeFilter,
|
||||
options: QemuAsanOptions,
|
||||
) -> Self {
|
||||
Self::with_error_callback(rt, filter, Box::new(asan_report), options)
|
||||
@ -922,12 +925,12 @@ impl QemuAsanHelper {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasInstrumentationFilter for QemuAsanHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationFilter {
|
||||
impl HasInstrumentationFilter<QemuInstrumentationAddressRangeFilter> for QemuAsanHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationAddressRangeFilter {
|
||||
&self.filter
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter {
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationAddressRangeFilter {
|
||||
&mut self.filter
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,10 @@ use thread_local::ThreadLocal;
|
||||
use crate::{
|
||||
capstone,
|
||||
emu::{ArchExtras, Emulator},
|
||||
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
helper::{
|
||||
HasInstrumentationFilter, IsFilter, QemuHelper, QemuHelperTuple,
|
||||
QemuInstrumentationAddressRangeFilter,
|
||||
},
|
||||
hooks::{Hook, QemuHooks},
|
||||
GuestAddr,
|
||||
};
|
||||
@ -215,7 +218,7 @@ pub struct QemuCallTracerHelper<T>
|
||||
where
|
||||
T: CallTraceCollectorTuple,
|
||||
{
|
||||
filter: QemuInstrumentationFilter,
|
||||
filter: QemuInstrumentationAddressRangeFilter,
|
||||
cs: Capstone,
|
||||
collectors: Option<T>,
|
||||
}
|
||||
@ -225,7 +228,7 @@ where
|
||||
T: CallTraceCollectorTuple,
|
||||
{
|
||||
#[must_use]
|
||||
pub fn new(filter: QemuInstrumentationFilter, collectors: T) -> Self {
|
||||
pub fn new(filter: QemuInstrumentationAddressRangeFilter, collectors: T) -> Self {
|
||||
Self {
|
||||
filter,
|
||||
cs: capstone().detail(true).build().unwrap(),
|
||||
@ -380,15 +383,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> HasInstrumentationFilter for QemuCallTracerHelper<T>
|
||||
impl<T> HasInstrumentationFilter<QemuInstrumentationAddressRangeFilter> for QemuCallTracerHelper<T>
|
||||
where
|
||||
T: CallTraceCollectorTuple,
|
||||
{
|
||||
fn filter(&self) -> &QemuInstrumentationFilter {
|
||||
fn filter(&self) -> &QemuInstrumentationAddressRangeFilter {
|
||||
&self.filter
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter {
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationAddressRangeFilter {
|
||||
&mut self.filter
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,8 @@ use crate::{
|
||||
};
|
||||
use crate::{
|
||||
helper::{
|
||||
hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter,
|
||||
hash_me, HasInstrumentationFilter, IsFilter, QemuHelper, QemuHelperTuple,
|
||||
QemuInstrumentationAddressRangeFilter,
|
||||
},
|
||||
hooks::{Hook, QemuHooks},
|
||||
GuestAddr,
|
||||
@ -48,12 +49,12 @@ libafl_bolts::impl_serdeany!(QemuCmpsMapMetadata);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct QemuCmpLogHelper {
|
||||
filter: QemuInstrumentationFilter,
|
||||
filter: QemuInstrumentationAddressRangeFilter,
|
||||
}
|
||||
|
||||
impl QemuCmpLogHelper {
|
||||
#[must_use]
|
||||
pub fn new(filter: QemuInstrumentationFilter) -> Self {
|
||||
pub fn new(filter: QemuInstrumentationAddressRangeFilter) -> Self {
|
||||
Self { filter }
|
||||
}
|
||||
|
||||
@ -65,16 +66,16 @@ impl QemuCmpLogHelper {
|
||||
|
||||
impl Default for QemuCmpLogHelper {
|
||||
fn default() -> Self {
|
||||
Self::new(QemuInstrumentationFilter::None)
|
||||
Self::new(QemuInstrumentationAddressRangeFilter::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasInstrumentationFilter for QemuCmpLogHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationFilter {
|
||||
impl HasInstrumentationFilter<QemuInstrumentationAddressRangeFilter> for QemuCmpLogHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationAddressRangeFilter {
|
||||
&self.filter
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter {
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationAddressRangeFilter {
|
||||
&mut self.filter
|
||||
}
|
||||
}
|
||||
@ -99,12 +100,12 @@ where
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct QemuCmpLogChildHelper {
|
||||
filter: QemuInstrumentationFilter,
|
||||
filter: QemuInstrumentationAddressRangeFilter,
|
||||
}
|
||||
|
||||
impl QemuCmpLogChildHelper {
|
||||
#[must_use]
|
||||
pub fn new(filter: QemuInstrumentationFilter) -> Self {
|
||||
pub fn new(filter: QemuInstrumentationAddressRangeFilter) -> Self {
|
||||
Self { filter }
|
||||
}
|
||||
|
||||
@ -116,7 +117,7 @@ impl QemuCmpLogChildHelper {
|
||||
|
||||
impl Default for QemuCmpLogChildHelper {
|
||||
fn default() -> Self {
|
||||
Self::new(QemuInstrumentationFilter::None)
|
||||
Self::new(QemuInstrumentationAddressRangeFilter::None)
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,14 +220,14 @@ pub extern "C" fn trace_cmp8_cmplog(_: *const (), id: u64, v0: u64, v1: u64) {
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
#[derive(Debug)]
|
||||
pub struct QemuCmpLogRoutinesHelper {
|
||||
filter: QemuInstrumentationFilter,
|
||||
filter: QemuInstrumentationAddressRangeFilter,
|
||||
cs: Capstone,
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
impl QemuCmpLogRoutinesHelper {
|
||||
#[must_use]
|
||||
pub fn new(filter: QemuInstrumentationFilter) -> Self {
|
||||
pub fn new(filter: QemuInstrumentationAddressRangeFilter) -> Self {
|
||||
Self {
|
||||
filter,
|
||||
cs: capstone().detail(true).build().unwrap(),
|
||||
@ -348,12 +349,12 @@ impl QemuCmpLogRoutinesHelper {
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
impl HasInstrumentationFilter for QemuCmpLogRoutinesHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationFilter {
|
||||
impl HasInstrumentationFilter<QemuInstrumentationAddressRangeFilter> for QemuCmpLogRoutinesHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationAddressRangeFilter {
|
||||
&self.filter
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter {
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationAddressRangeFilter {
|
||||
&mut self.filter
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,10 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
emu::{GuestAddr, GuestUsize},
|
||||
helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
helper::{
|
||||
HasInstrumentationFilter, IsFilter, QemuHelper, QemuHelperTuple,
|
||||
QemuInstrumentationAddressRangeFilter,
|
||||
},
|
||||
hooks::{Hook, QemuHooks},
|
||||
Emulator,
|
||||
};
|
||||
@ -39,7 +42,7 @@ libafl_bolts::impl_serdeany!(QemuDrCovMetadata);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct QemuDrCovHelper {
|
||||
filter: QemuInstrumentationFilter,
|
||||
filter: QemuInstrumentationAddressRangeFilter,
|
||||
module_mapping: RangeMap<usize, (u16, String)>,
|
||||
filename: PathBuf,
|
||||
full_trace: bool,
|
||||
@ -50,7 +53,7 @@ impl QemuDrCovHelper {
|
||||
#[must_use]
|
||||
#[allow(clippy::let_underscore_untyped)]
|
||||
pub fn new(
|
||||
filter: QemuInstrumentationFilter,
|
||||
filter: QemuInstrumentationAddressRangeFilter,
|
||||
module_mapping: RangeMap<usize, (u16, String)>,
|
||||
filename: PathBuf,
|
||||
full_trace: bool,
|
||||
@ -75,12 +78,12 @@ impl QemuDrCovHelper {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasInstrumentationFilter for QemuDrCovHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationFilter {
|
||||
impl HasInstrumentationFilter<QemuInstrumentationAddressRangeFilter> for QemuDrCovHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationAddressRangeFilter {
|
||||
&self.filter
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter {
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationAddressRangeFilter {
|
||||
&mut self.filter
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,14 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
emu::GuestAddr,
|
||||
helper::{
|
||||
hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter,
|
||||
hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple,
|
||||
QemuInstrumentationAddressRangeFilter,
|
||||
},
|
||||
hooks::{Hook, QemuHooks},
|
||||
IsFilter,
|
||||
};
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
use crate::{helper::QemuInstrumentationPagingFilter, GuestPhysAddr};
|
||||
|
||||
#[cfg_attr(
|
||||
any(not(feature = "serdeany_autoreg"), miri),
|
||||
@ -38,48 +42,112 @@ impl QemuEdgesMapMetadata {
|
||||
|
||||
libafl_bolts::impl_serdeany!(QemuEdgesMapMetadata);
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
#[derive(Debug)]
|
||||
pub struct QemuEdgeCoverageHelper {
|
||||
filter: QemuInstrumentationFilter,
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
use_hitcounts: bool,
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
#[derive(Debug)]
|
||||
pub struct QemuEdgeCoverageHelper {
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
paging_filter: QemuInstrumentationPagingFilter,
|
||||
use_hitcounts: bool,
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
impl QemuEdgeCoverageHelper {
|
||||
#[must_use]
|
||||
pub fn new(filter: QemuInstrumentationFilter) -> Self {
|
||||
pub fn new(address_filter: QemuInstrumentationAddressRangeFilter) -> Self {
|
||||
Self {
|
||||
filter,
|
||||
address_filter,
|
||||
use_hitcounts: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn without_hitcounts(filter: QemuInstrumentationFilter) -> Self {
|
||||
pub fn without_hitcounts(address_filter: QemuInstrumentationAddressRangeFilter) -> Self {
|
||||
Self {
|
||||
filter,
|
||||
address_filter,
|
||||
use_hitcounts: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn must_instrument(&self, addr: GuestAddr) -> bool {
|
||||
self.filter.allowed(addr)
|
||||
self.address_filter.allowed(addr)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
impl QemuEdgeCoverageHelper {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
paging_filter: QemuInstrumentationPagingFilter,
|
||||
) -> Self {
|
||||
Self {
|
||||
address_filter,
|
||||
paging_filter,
|
||||
use_hitcounts: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn without_hitcounts(
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
paging_filter: QemuInstrumentationPagingFilter,
|
||||
) -> Self {
|
||||
Self {
|
||||
address_filter,
|
||||
paging_filter,
|
||||
use_hitcounts: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn must_instrument(&self, addr: GuestAddr, paging_id: Option<GuestPhysAddr>) -> bool {
|
||||
self.address_filter.allowed(addr) && self.paging_filter.allowed(paging_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
impl Default for QemuEdgeCoverageHelper {
|
||||
fn default() -> Self {
|
||||
Self::new(QemuInstrumentationFilter::None)
|
||||
Self::new(QemuInstrumentationAddressRangeFilter::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasInstrumentationFilter for QemuEdgeCoverageHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationFilter {
|
||||
&self.filter
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
impl Default for QemuEdgeCoverageHelper {
|
||||
fn default() -> Self {
|
||||
Self::new(
|
||||
QemuInstrumentationAddressRangeFilter::None,
|
||||
QemuInstrumentationPagingFilter::None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter {
|
||||
&mut self.filter
|
||||
impl HasInstrumentationFilter<QemuInstrumentationAddressRangeFilter> for QemuEdgeCoverageHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationAddressRangeFilter {
|
||||
&self.address_filter
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationAddressRangeFilter {
|
||||
&mut self.address_filter
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
impl HasInstrumentationFilter<QemuInstrumentationPagingFilter> for QemuEdgeCoverageHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationPagingFilter {
|
||||
&self.paging_filter
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationPagingFilter {
|
||||
&mut self.paging_filter
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,48 +189,114 @@ where
|
||||
|
||||
pub type QemuCollidingEdgeCoverageHelper = QemuEdgeCoverageChildHelper;
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
#[derive(Debug)]
|
||||
pub struct QemuEdgeCoverageChildHelper {
|
||||
filter: QemuInstrumentationFilter,
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
use_hitcounts: bool,
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
#[derive(Debug)]
|
||||
pub struct QemuEdgeCoverageChildHelper {
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
paging_filter: QemuInstrumentationPagingFilter,
|
||||
use_hitcounts: bool,
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
impl QemuEdgeCoverageChildHelper {
|
||||
#[must_use]
|
||||
pub fn new(filter: QemuInstrumentationFilter) -> Self {
|
||||
pub fn new(address_filter: QemuInstrumentationAddressRangeFilter) -> Self {
|
||||
Self {
|
||||
filter,
|
||||
address_filter,
|
||||
use_hitcounts: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn without_hitcounts(filter: QemuInstrumentationFilter) -> Self {
|
||||
pub fn without_hitcounts(address_filter: QemuInstrumentationAddressRangeFilter) -> Self {
|
||||
Self {
|
||||
filter,
|
||||
address_filter,
|
||||
use_hitcounts: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn must_instrument(&self, addr: GuestAddr) -> bool {
|
||||
self.filter.allowed(addr)
|
||||
self.address_filter.allowed(addr)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
impl QemuEdgeCoverageChildHelper {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
paging_filter: QemuInstrumentationPagingFilter,
|
||||
) -> Self {
|
||||
Self {
|
||||
address_filter,
|
||||
paging_filter,
|
||||
use_hitcounts: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn without_hitcounts(
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
paging_filter: QemuInstrumentationPagingFilter,
|
||||
) -> Self {
|
||||
Self {
|
||||
address_filter,
|
||||
paging_filter,
|
||||
use_hitcounts: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn must_instrument(&self, addr: GuestAddr, paging_id: Option<GuestPhysAddr>) -> bool {
|
||||
self.address_filter.allowed(addr) && self.paging_filter.allowed(paging_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
impl Default for QemuEdgeCoverageChildHelper {
|
||||
fn default() -> Self {
|
||||
Self::new(QemuInstrumentationFilter::None)
|
||||
Self::new(QemuInstrumentationAddressRangeFilter::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasInstrumentationFilter for QemuEdgeCoverageChildHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationFilter {
|
||||
&self.filter
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
impl Default for QemuEdgeCoverageChildHelper {
|
||||
fn default() -> Self {
|
||||
Self::new(
|
||||
QemuInstrumentationAddressRangeFilter::None,
|
||||
QemuInstrumentationPagingFilter::None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter {
|
||||
&mut self.filter
|
||||
impl HasInstrumentationFilter<QemuInstrumentationAddressRangeFilter>
|
||||
for QemuEdgeCoverageChildHelper
|
||||
{
|
||||
fn filter(&self) -> &QemuInstrumentationAddressRangeFilter {
|
||||
&self.address_filter
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationAddressRangeFilter {
|
||||
&mut self.address_filter
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
impl HasInstrumentationFilter<QemuInstrumentationPagingFilter> for QemuEdgeCoverageChildHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationPagingFilter {
|
||||
&self.paging_filter
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationPagingFilter {
|
||||
&mut self.paging_filter
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,48 +325,114 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
#[derive(Debug)]
|
||||
pub struct QemuEdgeCoverageClassicHelper {
|
||||
filter: QemuInstrumentationFilter,
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
use_hitcounts: bool,
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
#[derive(Debug)]
|
||||
pub struct QemuEdgeCoverageClassicHelper {
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
paging_filter: QemuInstrumentationPagingFilter,
|
||||
use_hitcounts: bool,
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
impl QemuEdgeCoverageClassicHelper {
|
||||
#[must_use]
|
||||
pub fn new(filter: QemuInstrumentationFilter) -> Self {
|
||||
pub fn new(address_filter: QemuInstrumentationAddressRangeFilter) -> Self {
|
||||
Self {
|
||||
filter,
|
||||
address_filter,
|
||||
use_hitcounts: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn without_hitcounts(filter: QemuInstrumentationFilter) -> Self {
|
||||
pub fn without_hitcounts(address_filter: QemuInstrumentationAddressRangeFilter) -> Self {
|
||||
Self {
|
||||
filter,
|
||||
address_filter,
|
||||
use_hitcounts: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn must_instrument(&self, addr: GuestAddr) -> bool {
|
||||
self.filter.allowed(addr)
|
||||
self.address_filter.allowed(addr)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
impl QemuEdgeCoverageClassicHelper {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
paging_filter: QemuInstrumentationPagingFilter,
|
||||
) -> Self {
|
||||
Self {
|
||||
address_filter,
|
||||
paging_filter,
|
||||
use_hitcounts: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn without_hitcounts(
|
||||
address_filter: QemuInstrumentationAddressRangeFilter,
|
||||
paging_filter: QemuInstrumentationPagingFilter,
|
||||
) -> Self {
|
||||
Self {
|
||||
address_filter,
|
||||
paging_filter,
|
||||
use_hitcounts: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn must_instrument(&self, addr: GuestAddr, paging_id: Option<GuestPhysAddr>) -> bool {
|
||||
self.address_filter.allowed(addr) && self.paging_filter.allowed(paging_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
impl Default for QemuEdgeCoverageClassicHelper {
|
||||
fn default() -> Self {
|
||||
Self::new(QemuInstrumentationFilter::None)
|
||||
Self::new(QemuInstrumentationAddressRangeFilter::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasInstrumentationFilter for QemuEdgeCoverageClassicHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationFilter {
|
||||
&self.filter
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
impl Default for QemuEdgeCoverageClassicHelper {
|
||||
fn default() -> Self {
|
||||
Self::new(
|
||||
QemuInstrumentationAddressRangeFilter::None,
|
||||
QemuInstrumentationPagingFilter::None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter {
|
||||
&mut self.filter
|
||||
impl HasInstrumentationFilter<QemuInstrumentationAddressRangeFilter>
|
||||
for QemuEdgeCoverageClassicHelper
|
||||
{
|
||||
fn filter(&self) -> &QemuInstrumentationAddressRangeFilter {
|
||||
&self.address_filter
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationAddressRangeFilter {
|
||||
&mut self.address_filter
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
impl HasInstrumentationFilter<QemuInstrumentationPagingFilter> for QemuEdgeCoverageClassicHelper {
|
||||
fn filter(&self) -> &QemuInstrumentationPagingFilter {
|
||||
&self.paging_filter
|
||||
}
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationPagingFilter {
|
||||
&mut self.paging_filter
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,10 +477,26 @@ where
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
if let Some(h) = hooks.helpers().match_first_type::<QemuEdgeCoverageHelper>() {
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
{
|
||||
if !h.must_instrument(src) && !h.must_instrument(dest) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
{
|
||||
let paging_id = hooks
|
||||
.emulator()
|
||||
.current_cpu()
|
||||
.map(|cpu| cpu.get_current_paging_id())
|
||||
.flatten();
|
||||
|
||||
if !h.must_instrument(src, paging_id) && !h.must_instrument(dest, paging_id) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
let state = state.expect("The gen_unique_edge_ids hook works only for in-process fuzzing");
|
||||
if state.metadata_map().get::<QemuEdgesMapMetadata>().is_none() {
|
||||
state.add_metadata(QemuEdgesMapMetadata::new());
|
||||
@ -339,9 +555,23 @@ where
|
||||
.helpers()
|
||||
.match_first_type::<QemuEdgeCoverageChildHelper>()
|
||||
{
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
if !h.must_instrument(src) && !h.must_instrument(dest) {
|
||||
return None;
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
{
|
||||
let paging_id = hooks
|
||||
.emulator()
|
||||
.current_cpu()
|
||||
.map(|cpu| cpu.get_current_paging_id())
|
||||
.flatten();
|
||||
|
||||
if !h.must_instrument(src, paging_id) && !h.must_instrument(dest, paging_id) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
// GuestAddress is u32 for 32 bit guests
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
@ -390,11 +620,26 @@ where
|
||||
if let Some(h) = hooks
|
||||
.helpers()
|
||||
.match_first_type::<QemuEdgeCoverageClassicHelper>()
|
||||
{
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
{
|
||||
if !h.must_instrument(pc) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
{
|
||||
let paging_id = hooks
|
||||
.emulator()
|
||||
.current_cpu()
|
||||
.map(|cpu| cpu.get_current_paging_id())
|
||||
.flatten();
|
||||
|
||||
if !h.must_instrument(pc, paging_id) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
// GuestAddress is u32 for 32 bit guests
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
Some(hash_me(pc as u64))
|
||||
|
@ -10,11 +10,8 @@ use core::{
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
use std::cell::OnceCell;
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
use std::{
|
||||
ffi::{CStr, CString},
|
||||
ptr::null_mut,
|
||||
};
|
||||
use std::{slice::from_raw_parts, str::from_utf8_unchecked};
|
||||
use std::{ffi::CStr, ptr::null_mut};
|
||||
use std::{ffi::CString, ptr, slice::from_raw_parts, str::from_utf8_unchecked};
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
use libc::c_int;
|
||||
@ -393,6 +390,9 @@ extern "C" {
|
||||
data: *const (),
|
||||
);
|
||||
fn libafl_qemu_gdb_reply(buf: *const u8, len: usize);
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
fn libafl_qemu_current_paging_id(cpu: CPUStatePtr) -> GuestPhysAddr;
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
@ -589,6 +589,18 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
#[must_use]
|
||||
pub fn get_current_paging_id(&self) -> Option<GuestPhysAddr> {
|
||||
let paging_id = unsafe { libafl_qemu_current_paging_id(self.ptr) };
|
||||
|
||||
if paging_id == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(paging_id)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO expose tlb_set_dirty and tlb_reset_dirty
|
||||
|
||||
/// Write a value to a guest address.
|
||||
@ -945,8 +957,12 @@ impl Emulator {
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
let argc = argc as i32;
|
||||
|
||||
let args: Vec<String> = args.iter().map(|x| x.clone() + "\0").collect();
|
||||
let argv: Vec<*const u8> = args.iter().map(|x| x.as_bytes().as_ptr()).collect();
|
||||
let args: Vec<CString> = args
|
||||
.iter()
|
||||
.map(|x| CString::new(x.clone()).unwrap())
|
||||
.collect();
|
||||
let mut argv: Vec<*const u8> = args.iter().map(|x| x.as_ptr() as *const u8).collect();
|
||||
argv.push(ptr::null()); // argv is always null terminated.
|
||||
let env_strs: Vec<String> = env
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{}={}\0", &k, &v))
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::{fmt::Debug, ops::Range};
|
||||
use std::{collections::HashSet, hash};
|
||||
|
||||
use libafl::{executors::ExitKind, inputs::UsesInput, observers::ObserversTuple};
|
||||
use libafl_bolts::tuples::{MatchFirstType, SplitBorrowExtractFirstType};
|
||||
@ -6,6 +7,7 @@ use libafl_bolts::tuples::{MatchFirstType, SplitBorrowExtractFirstType};
|
||||
use crate::{
|
||||
emu::{Emulator, GuestAddr},
|
||||
hooks::QemuHooks,
|
||||
GuestPhysAddr,
|
||||
};
|
||||
|
||||
/// A helper for `libafl_qemu`.
|
||||
@ -143,49 +145,83 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum QemuInstrumentationFilter {
|
||||
AllowList(Vec<Range<GuestAddr>>),
|
||||
DenyList(Vec<Range<GuestAddr>>),
|
||||
#[derive(Debug)]
|
||||
pub enum QemuFilterList<T: IsFilter + Debug> {
|
||||
AllowList(T),
|
||||
DenyList(T),
|
||||
None,
|
||||
}
|
||||
|
||||
impl QemuInstrumentationFilter {
|
||||
#[must_use]
|
||||
pub fn allowed(&self, addr: GuestAddr) -> bool {
|
||||
impl<T> IsFilter for QemuFilterList<T>
|
||||
where
|
||||
T: IsFilter,
|
||||
{
|
||||
type FilterParameter = T::FilterParameter;
|
||||
|
||||
fn allowed(&self, filter_parameter: Self::FilterParameter) -> bool {
|
||||
match self {
|
||||
QemuInstrumentationFilter::AllowList(l) => {
|
||||
for rng in l {
|
||||
QemuFilterList::AllowList(allow_list) => allow_list.allowed(filter_parameter),
|
||||
QemuFilterList::DenyList(deny_list) => !deny_list.allowed(filter_parameter),
|
||||
QemuFilterList::None => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type QemuInstrumentationPagingFilter = QemuFilterList<HashSet<GuestPhysAddr>>;
|
||||
|
||||
impl<H: hash::BuildHasher> IsFilter for HashSet<GuestPhysAddr, H> {
|
||||
type FilterParameter = Option<GuestPhysAddr>;
|
||||
|
||||
fn allowed(&self, paging_id: Self::FilterParameter) -> bool {
|
||||
paging_id.is_some_and(|pid| self.contains(&pid))
|
||||
}
|
||||
}
|
||||
|
||||
pub type QemuInstrumentationAddressRangeFilter = QemuFilterList<Vec<Range<GuestAddr>>>;
|
||||
|
||||
impl IsFilter for Vec<Range<GuestAddr>> {
|
||||
type FilterParameter = GuestAddr;
|
||||
|
||||
fn allowed(&self, addr: Self::FilterParameter) -> bool {
|
||||
for rng in self {
|
||||
if rng.contains(&addr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
QemuInstrumentationFilter::DenyList(l) => {
|
||||
for rng in l {
|
||||
if rng.contains(&addr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
QemuInstrumentationFilter::None => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasInstrumentationFilter {
|
||||
fn filter(&self) -> &QemuInstrumentationFilter;
|
||||
pub trait HasInstrumentationFilter<F>
|
||||
where
|
||||
F: IsFilter,
|
||||
{
|
||||
fn filter(&self) -> &F;
|
||||
|
||||
fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter;
|
||||
fn filter_mut(&mut self) -> &mut F;
|
||||
|
||||
fn update_filter(&mut self, filter: QemuInstrumentationFilter, emu: &Emulator) {
|
||||
fn update_filter(&mut self, filter: F, emu: &Emulator) {
|
||||
*self.filter_mut() = filter;
|
||||
emu.flush_jit();
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IsFilter: Debug {
|
||||
type FilterParameter;
|
||||
|
||||
fn allowed(&self, filter_parameter: Self::FilterParameter) -> bool;
|
||||
}
|
||||
|
||||
pub trait IsAddressFilter: IsFilter<FilterParameter = GuestAddr> {}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
pub trait IsPagingFilter: IsFilter<FilterParameter = Option<GuestPhysAddr>> {}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
impl IsPagingFilter for QemuInstrumentationPagingFilter {}
|
||||
|
||||
impl IsAddressFilter for QemuInstrumentationAddressRangeFilter {}
|
||||
|
||||
#[must_use]
|
||||
pub fn hash_me(mut x: u64) -> u64 {
|
||||
x = (x.overflowing_shr(16).0 ^ x).overflowing_mul(0x45d9f3b).0;
|
||||
|
@ -87,7 +87,9 @@ macro_rules! hook_to_repr {
|
||||
}
|
||||
|
||||
static mut QEMU_HOOKS_PTR: *const c_void = ptr::null();
|
||||
unsafe fn get_qemu_hooks<'a, QT, S>() -> &'a mut QemuHooks<QT, S>
|
||||
|
||||
#[must_use]
|
||||
pub unsafe fn get_qemu_hooks<'a, QT, S>() -> &'a mut QemuHooks<QT, S>
|
||||
where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
|
Loading…
x
Reference in New Issue
Block a user