diff --git a/crates/libafl/src/common/nautilus/README.md b/crates/libafl/src/common/nautilus/README.md
index 9f91e27329..32f0afe898 100644
--- a/crates/libafl/src/common/nautilus/README.md
+++ b/crates/libafl/src/common/nautilus/README.md
@@ -1,4 +1,4 @@
-# Nautilus 2.0 LibAFL Mutator
+# Nautilus 2.0 `LibAFL` Mutator
Nautilus is a coverage guided, grammar-based mutator. You can use it to improve your test coverage and find more bugs. By specifying the grammar of semi-valid inputs, Nautilus is able to perform complex mutation and to uncover more interesting test cases. Many of the ideas behind the original fuzzer are documented in a paper published at NDSS 2019.
@@ -7,7 +7,7 @@ Nautilus is a coverage guided, grammar-based mutator. You can use it to improve
Version 2.0 has added many improvements to this early prototype.
-Features from version 2.0 we support in LibAFL:
+Features from version 2.0 we support in `LibAFL`:
* Support for grammars specified in python
* Support for non-context free grammars using python scripts to generate inputs from the structure
diff --git a/crates/libafl/src/common/nautilus/mod.rs b/crates/libafl/src/common/nautilus/mod.rs
index 215c00cb6f..7130110069 100644
--- a/crates/libafl/src/common/nautilus/mod.rs
+++ b/crates/libafl/src/common/nautilus/mod.rs
@@ -1,4 +1,4 @@
-//! LibAFL version of the [`Nautilus`](https://github.com/nautilus-fuzz/nautilus) grammar fuzzer
+//! `LibAFL` version of the [`Nautilus`](https://github.com/nautilus-fuzz/nautilus) grammar fuzzer
#![doc = include_str!("README.md")]
#[allow(missing_docs)]
diff --git a/crates/libafl/src/executors/command.rs b/crates/libafl/src/executors/command.rs
index a57a30c486..597ee9b4d4 100644
--- a/crates/libafl/src/executors/command.rs
+++ b/crates/libafl/src/executors/command.rs
@@ -235,6 +235,7 @@ pub struct PTraceCommandConfigurator {
}
#[cfg(all(feature = "intel_pt", target_os = "linux"))]
+#[allow(unreachable_code)]
impl CommandConfigurator for PTraceCommandConfigurator {
fn spawn_child(&mut self, target_bytes: OwnedSlice<'_, u8>) -> Result {
use nix::{
diff --git a/crates/libafl_bolts/src/rands/mod.rs b/crates/libafl_bolts/src/rands/mod.rs
index 14b5c50ce9..8ad2e94ea7 100644
--- a/crates/libafl_bolts/src/rands/mod.rs
+++ b/crates/libafl_bolts/src/rands/mod.rs
@@ -567,9 +567,9 @@ pub mod pybind {
#[pyclass(unsendable, name = "StdRand")]
#[expect(clippy::unsafe_derive_deserialize)]
#[derive(Serialize, Deserialize, Debug, Clone)]
- /// Python class for StdRand
+ /// Python class for `StdRand`
pub struct PythonStdRand {
- /// Rust wrapped StdRand object
+ /// Rust wrapped `StdRand` object
pub inner: StdRand,
}
diff --git a/crates/libafl_frida/src/helper.rs b/crates/libafl_frida/src/helper.rs
index cd65bb362f..5894ebaf1a 100644
--- a/crates/libafl_frida/src/helper.rs
+++ b/crates/libafl_frida/src/helper.rs
@@ -699,26 +699,26 @@ where
};
#[cfg(target_arch = "x86_64")]
- if let Some(details) = res {
- if let Some(rt) = runtimes.match_first_type_mut::() {
- let start = output.writer().pc();
- rt.emit_shadow_check(
- address,
- output,
- instr.bytes().len(),
- details.0,
- details.1,
- details.2,
- details.3,
- details.4,
- );
- log::trace!(
- "emitted shadow_check for {:x} at {:x}-{:x}",
- address,
- start,
- output.writer().pc()
- );
- }
+ if let Some(details) = res
+ && let Some(rt) = runtimes.match_first_type_mut::()
+ {
+ let start = output.writer().pc();
+ rt.emit_shadow_check(
+ address,
+ output,
+ instr.bytes().len(),
+ details.0,
+ details.1,
+ details.2,
+ details.3,
+ details.4,
+ );
+ log::trace!(
+ "emitted shadow_check for {:x} at {:x}-{:x}",
+ address,
+ start,
+ output.writer().pc()
+ );
}
#[cfg(target_arch = "aarch64")]
@@ -740,21 +740,13 @@ where
feature = "cmplog",
any(target_arch = "aarch64", target_arch = "x86_64")
))]
- if let Some(rt) = runtimes.match_first_type_mut::() {
- if let Some((op1, op2, shift, special_case)) =
+ if let Some(rt) = runtimes.match_first_type_mut::()
+ && let Some((op1, op2, shift, special_case)) =
CmpLogRuntime::cmplog_is_interesting_instruction(decoder, address, instr)
- //change this as well
- {
- //emit code that saves the relevant data in runtime(passes it to x0, x1)
- rt.emit_comparison_handling(
- address,
- output,
- &op1,
- &op2,
- &shift,
- &special_case,
- );
- }
+ //change this as well
+ {
+ //emit code that saves the relevant data in runtime(passes it to x0, x1)
+ rt.emit_comparison_handling(address, output, &op1, &op2, &shift, &special_case);
}
if let Some(rt) = runtimes.match_first_type_mut::() {
diff --git a/crates/libafl_qemu/src/elf.rs b/crates/libafl_qemu/src/elf.rs
index fba390a0c6..300475755e 100644
--- a/crates/libafl_qemu/src/elf.rs
+++ b/crates/libafl_qemu/src/elf.rs
@@ -49,26 +49,26 @@ impl<'a> EasyElf<'a> {
#[must_use]
pub fn resolve_symbol(&self, name: &str, load_addr: GuestAddr) -> Option {
for sym in &self.elf.syms {
- if let Some(sym_name) = self.elf.strtab.get_at(sym.st_name) {
- if sym_name == name {
- return if sym.st_value == 0 {
- None
- } else if self.is_pic() {
- #[cfg(cpu_target = "arm")]
- // Required because of arm interworking addresses aka bit(0) for thumb mode
- let addr = (sym.st_value as GuestAddr + load_addr) & !(0x1 as GuestAddr);
- #[cfg(not(cpu_target = "arm"))]
- let addr = sym.st_value as GuestAddr + load_addr;
- Some(addr)
- } else {
- #[cfg(cpu_target = "arm")]
- // Required because of arm interworking addresses aka bit(0) for thumb mode
- let addr = (sym.st_value as GuestAddr) & !(0x1 as GuestAddr);
- #[cfg(not(cpu_target = "arm"))]
- let addr = sym.st_value as GuestAddr;
- Some(addr)
- };
- }
+ if let Some(sym_name) = self.elf.strtab.get_at(sym.st_name)
+ && sym_name == name
+ {
+ return if sym.st_value == 0 {
+ None
+ } else if self.is_pic() {
+ #[cfg(cpu_target = "arm")]
+ // Required because of arm interworking addresses aka bit(0) for thumb mode
+ let addr = (sym.st_value as GuestAddr + load_addr) & !(0x1 as GuestAddr);
+ #[cfg(not(cpu_target = "arm"))]
+ let addr = sym.st_value as GuestAddr + load_addr;
+ Some(addr)
+ } else {
+ #[cfg(cpu_target = "arm")]
+ // Required because of arm interworking addresses aka bit(0) for thumb mode
+ let addr = (sym.st_value as GuestAddr) & !(0x1 as GuestAddr);
+ #[cfg(not(cpu_target = "arm"))]
+ let addr = sym.st_value as GuestAddr;
+ Some(addr)
+ };
}
}
None
diff --git a/crates/libafl_qemu/src/modules/cmplog.rs b/crates/libafl_qemu/src/modules/cmplog.rs
index 0572036d59..7c92e034b3 100644
--- a/crates/libafl_qemu/src/modules/cmplog.rs
+++ b/crates/libafl_qemu/src/modules/cmplog.rs
@@ -204,11 +204,12 @@ where
I: Unpin,
S: Unpin + HasMetadata,
{
- if let Some(h) = emulator_modules.get::() {
- if !h.must_instrument(pc) {
- return None;
- }
+ if let Some(h) = emulator_modules.get::()
+ && !h.must_instrument(pc)
+ {
+ return None;
}
+
let state = state.expect("The gen_unique_cmp_ids hook works only for in-process fuzzing. Is the Executor initialized?");
if state.metadata_map().get::().is_none() {
state.add_metadata(QemuCmpsMapMetadata::new());
@@ -238,11 +239,12 @@ where
I: Unpin,
S: HasMetadata + Unpin,
{
- if let Some(h) = emulator_modules.get::() {
- if !h.must_instrument(pc) {
- return None;
- }
+ if let Some(h) = emulator_modules.get::()
+ && !h.must_instrument(pc)
+ {
+ return None;
}
+
Some(hash_64_fast(pc.into()) & (CMPLOG_MAP_W as u64 - 1))
}
diff --git a/crates/libafl_qemu/src/modules/usermode/asan_guest.rs b/crates/libafl_qemu/src/modules/usermode/asan_guest.rs
index 54d55abf14..2fa7e9c2e0 100644
--- a/crates/libafl_qemu/src/modules/usermode/asan_guest.rs
+++ b/crates/libafl_qemu/src/modules/usermode/asan_guest.rs
@@ -116,13 +116,12 @@ where
}
/* Don't sanitize the sanitizer! */
- if let Some(asan_mappings) = &h.asan_mappings {
- if asan_mappings
+ if let Some(asan_mappings) = &h.asan_mappings
+ && asan_mappings
.iter()
.any(|m| m.start() <= pc && pc < m.end())
- {
- return None;
- }
+ {
+ return None;
}
let size = info.size();
diff --git a/crates/libafl_qemu/src/modules/usermode/asan_host.rs b/crates/libafl_qemu/src/modules/usermode/asan_host.rs
index 8062845392..d4a92f2155 100644
--- a/crates/libafl_qemu/src/modules/usermode/asan_host.rs
+++ b/crates/libafl_qemu/src/modules/usermode/asan_host.rs
@@ -1199,13 +1199,12 @@ where
}
// Don't sanitize the sanitizer!
- if let Some(asan_mappings) = &h.asan_mappings {
- if asan_mappings
+ if let Some(asan_mappings) = &h.asan_mappings
+ && asan_mappings
.iter()
.any(|m| m.start() <= pc && pc < m.end())
- {
- return None;
- }
+ {
+ return None;
}
Some(pc.into())
@@ -1296,13 +1295,12 @@ where
}
// Don't sanitize the sanitizer!
- if let Some(asan_mappings) = &h.asan_mappings {
- if asan_mappings
+ if let Some(asan_mappings) = &h.asan_mappings
+ && asan_mappings
.iter()
.any(|m| m.start() <= pc && pc < m.end())
- {
- return Some(0);
- }
+ {
+ return Some(0);
}
Some(pc.into())
diff --git a/crates/libafl_qemu/src/modules/usermode/snapshot.rs b/crates/libafl_qemu/src/modules/usermode/snapshot.rs
index 0062c8a534..421728a893 100644
--- a/crates/libafl_qemu/src/modules/usermode/snapshot.rs
+++ b/crates/libafl_qemu/src/modules/usermode/snapshot.rs
@@ -26,7 +26,10 @@ use crate::{
modules::{
EmulatorModule, EmulatorModuleTuple,
asan_host::AsanHostModule,
- utils::filters::{HasAddressFilter, NOP_ADDRESS_FILTER, NopAddressFilter},
+ utils::{
+ filters::{HasAddressFilter, NOP_ADDRESS_FILTER, NopAddressFilter},
+ logic::OptionalModule,
+ },
},
qemu::{Hook, SyscallHookResult},
};
@@ -842,8 +845,15 @@ pub fn trace_write_snapshot(
I: Unpin,
S: Unpin,
{
- let h = emulator_modules.get_mut::().unwrap();
- h.access(addr, SIZE);
+ if let Some(h) = emulator_modules.get_mut::() {
+ h.access(addr, SIZE);
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ h.access(addr, SIZE);
+ }
}
pub fn trace_write_n_snapshot(
@@ -859,8 +869,15 @@ pub fn trace_write_n_snapshot(
I: Unpin,
S: Unpin,
{
- let h = emulator_modules.get_mut::().unwrap();
- h.access(addr, size);
+ if let Some(h) = emulator_modules.get_mut::() {
+ h.access(addr, size);
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ h.access(addr, size);
+ }
}
/// Do not consider munmap syscalls that are not allowed
@@ -885,9 +902,18 @@ where
S: Unpin,
{
if i64::from(sys_num) == SYS_munmap {
- let h = emulator_modules.get_mut::().unwrap();
- if !h.is_unmap_allowed(a0 as GuestAddr, a1 as usize) {
- return SyscallHookResult::Skip(0);
+ if let Some(h) = emulator_modules.get_mut::() {
+ if !h.is_unmap_allowed(a0 as GuestAddr, a1 as usize) {
+ return SyscallHookResult::Skip(0);
+ }
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ if !h.is_unmap_allowed(a0 as GuestAddr, a1 as usize) {
+ return SyscallHookResult::Skip(0);
+ }
}
}
@@ -918,23 +944,50 @@ where
// NOT A COMPLETE LIST OF MEMORY EFFECTS
match i64::from(sys_num) {
SYS_read | SYS_pread64 => {
- let h = emulator_modules.get_mut::().unwrap();
- /*
- * Only note the access if the call is successful. And only mark the
- * portion of the buffer which has actually been modified.
- */
- if result != GuestAddr::MAX {
- h.access(a1, result as usize);
+ if let Some(h) = emulator_modules.get_mut::() {
+ /*
+ * Only note the access if the call is successful. And only mark the
+ * portion of the buffer which has actually been modified.
+ */
+ if result != GuestAddr::MAX {
+ h.access(a1, result as usize);
+ }
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ /*
+ * Only note the access if the call is successful. And only mark the
+ * portion of the buffer which has actually been modified.
+ */
+ if result != GuestAddr::MAX {
+ h.access(a1, result as usize);
+ }
}
}
SYS_readlinkat => {
- let h = emulator_modules.get_mut::().unwrap();
- h.access(a2, a3 as usize);
+ if let Some(h) = emulator_modules.get_mut::() {
+ h.access(a2, a3 as usize);
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ h.access(a2, a3 as usize);
+ }
}
#[cfg(not(cpu_target = "riscv32"))]
SYS_futex => {
- let h = emulator_modules.get_mut::().unwrap();
- h.access(a0, a3 as usize);
+ if let Some(h) = emulator_modules.get_mut::() {
+ h.access(a0, a3 as usize);
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ h.access(a0, a3 as usize);
+ }
}
#[cfg(not(any(
cpu_target = "arm",
@@ -945,26 +998,54 @@ where
)))]
SYS_newfstatat => {
if a2 != 0 {
- let h = emulator_modules.get_mut::().unwrap();
- h.access(a2, 4096); // stat is not greater than a page
+ if let Some(h) = emulator_modules.get_mut::() {
+ h.access(a2, 4096); // stat is not greater than a page
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ 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 = emulator_modules.get_mut::().unwrap();
- h.access(a2, 4096); // stat is not greater than a page
+ if let Some(h) = emulator_modules.get_mut::() {
+ h.access(a2, 4096); // stat is not greater than a page
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ h.access(a2, 4096); // stat is not greater than a page
+ }
}
}
#[cfg(not(cpu_target = "riscv32"))]
SYS_statfs | SYS_fstat | SYS_fstatfs => {
- let h = emulator_modules.get_mut::().unwrap();
- h.access(a1, 4096); // stat is not greater than a page
+ if let Some(h) = emulator_modules.get_mut::() {
+ h.access(a1, 4096); // stat is not greater than a page
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ h.access(a1, 4096); // stat is not greater than a page
+ }
}
#[cfg(not(cpu_target = "riscv32"))]
SYS_getrandom => {
- let h = emulator_modules.get_mut::().unwrap();
- h.access(a0, a1 as usize);
+ if let Some(h) = emulator_modules.get_mut::() {
+ h.access(a0, a1 as usize);
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ h.access(a0, a1 as usize);
+ }
}
SYS_brk => {
// We don't handle brk here. It is handled in the reset function only when it's needed.
@@ -983,33 +1064,72 @@ where
#[cfg(any(cpu_target = "arm", cpu_target = "mips", cpu_target = "riscv32"))]
if sys_const == SYS_mmap2 {
if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
- let h = emulator_modules.get_mut::().unwrap();
- h.add_mapped(result, a1 as usize, Some(prot));
+ if let Some(h) = emulator_modules.get_mut::() {
+ h.add_mapped(result, a1 as usize, Some(prot));
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ h.add_mapped(result, a1 as usize, Some(prot));
+ }
}
}
#[cfg(not(any(cpu_target = "arm", cpu_target = "riscv32")))]
- if sys_const == SYS_mmap {
- if let Ok(prot) = MmapPerms::try_from(a2 as i32) {
- let h = emulator_modules.get_mut::().unwrap();
+ if sys_const == SYS_mmap
+ && let Ok(prot) = MmapPerms::try_from(a2 as i32)
+ {
+ if let Some(h) = emulator_modules.get_mut::() {
+ h.add_mapped(result, a1 as usize, Some(prot));
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
h.add_mapped(result, a1 as usize, Some(prot));
}
}
if sys_const == SYS_mremap {
- let h = emulator_modules.get_mut::().unwrap();
- // TODO get the old permissions from the removed mapping
- h.remove_mapped(a0, a1 as usize);
- h.add_mapped(result, a2 as usize, None);
+ if let Some(h) = emulator_modules.get_mut::() {
+ // TODO get the old permissions from the removed mapping
+ h.remove_mapped(a0, a1 as usize);
+ h.add_mapped(result, a2 as usize, None);
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ // TODO get the old permissions from the removed mapping
+ 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 = emulator_modules.get_mut::().unwrap();
- h.change_mapped_perms(a0, a1 as usize, Some(prot));
+ if let Some(h) = emulator_modules.get_mut::() {
+ h.change_mapped_perms(a0, a1 as usize, Some(prot));
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ h.change_mapped_perms(a0, a1 as usize, Some(prot));
+ }
}
} else if sys_const == SYS_munmap {
- let h = emulator_modules.get_mut::().unwrap();
- if h.is_unmap_allowed(a0, a1 as usize) {
- h.remove_mapped(a0, a1 as usize);
+ if let Some(h) = emulator_modules.get_mut::() {
+ if h.is_unmap_allowed(a0, a1 as usize) {
+ h.remove_mapped(a0, a1 as usize);
+ }
+ } else {
+ let snap = emulator_modules
+ .get_mut::>()
+ .unwrap();
+ let h = snap.get_inner_module_mut();
+ if h.is_unmap_allowed(a0, a1 as usize) {
+ h.remove_mapped(a0, a1 as usize);
+ }
}
}
}
diff --git a/crates/libafl_qemu/src/modules/utils/logic.rs b/crates/libafl_qemu/src/modules/utils/logic.rs
new file mode 100644
index 0000000000..54865e15fa
--- /dev/null
+++ b/crates/libafl_qemu/src/modules/utils/logic.rs
@@ -0,0 +1,113 @@
+use std::fmt::Debug;
+
+use crate::modules::{EmulatorModule, EmulatorModuleTuple};
+
+#[derive(Debug)]
+pub struct OptionalModule {
+ enabled: bool,
+ module: MD,
+}
+
+impl OptionalModule {
+ pub fn new(enabled: bool, module: MD) -> Self {
+ Self { enabled, module }
+ }
+
+ pub fn get_inner_module_mut(&mut self) -> &mut MD {
+ &mut self.module
+ }
+}
+
+impl EmulatorModule for OptionalModule
+where
+ I: Unpin,
+ S: Unpin,
+ MD: EmulatorModule,
+{
+ const HOOKS_DO_SIDE_EFFECTS: bool = true;
+
+ fn pre_qemu_init(
+ &mut self,
+ emulator_modules: &mut crate::EmulatorModules,
+ qemu_params: &mut crate::QemuParams,
+ ) where
+ ET: EmulatorModuleTuple,
+ {
+ if self.enabled {
+ self.module.pre_qemu_init(emulator_modules, qemu_params);
+ }
+ }
+
+ fn post_qemu_init(
+ &mut self,
+ qemu: crate::Qemu,
+ emulator_modules: &mut crate::EmulatorModules,
+ ) where
+ ET: EmulatorModuleTuple,
+ {
+ if self.enabled {
+ self.module.post_qemu_init(qemu, emulator_modules);
+ }
+ }
+
+ fn first_exec(
+ &mut self,
+ qemu: crate::Qemu,
+ emulator_modules: &mut crate::EmulatorModules,
+ state: &mut S,
+ ) where
+ ET: EmulatorModuleTuple,
+ {
+ if self.enabled {
+ self.module.first_exec(qemu, emulator_modules, state);
+ }
+ }
+
+ fn pre_exec(
+ &mut self,
+ qemu: crate::Qemu,
+ emulator_modules: &mut crate::EmulatorModules,
+ state: &mut S,
+ input: &I,
+ ) where
+ ET: EmulatorModuleTuple,
+ {
+ if self.enabled {
+ self.module.pre_exec(qemu, emulator_modules, state, input);
+ }
+ }
+
+ fn post_exec(
+ &mut self,
+ qemu: crate::Qemu,
+ emulator_modules: &mut crate::EmulatorModules,
+ state: &mut S,
+ input: &I,
+ observers: &mut OT,
+ exit_kind: &mut libafl::executors::ExitKind,
+ ) where
+ OT: libafl::observers::ObserversTuple,
+ ET: EmulatorModuleTuple,
+ {
+ if self.enabled {
+ self.module
+ .post_exec(qemu, emulator_modules, state, input, observers, exit_kind);
+ }
+ }
+
+ unsafe fn on_crash(&mut self) {
+ if self.enabled {
+ unsafe {
+ self.module.on_crash();
+ }
+ }
+ }
+
+ unsafe fn on_timeout(&mut self) {
+ if self.enabled {
+ unsafe {
+ self.module.on_timeout();
+ }
+ }
+ }
+}
diff --git a/crates/libafl_qemu/src/modules/utils/mod.rs b/crates/libafl_qemu/src/modules/utils/mod.rs
index 6ad6c17029..83f60e60a1 100644
--- a/crates/libafl_qemu/src/modules/utils/mod.rs
+++ b/crates/libafl_qemu/src/modules/utils/mod.rs
@@ -1,4 +1,5 @@
pub mod filters;
+pub mod logic;
#[cfg(feature = "usermode")]
pub use addr2line::*;
diff --git a/crates/libafl_sugar/src/forkserver.rs b/crates/libafl_sugar/src/forkserver.rs
index aacbf55d98..2f29e852ae 100644
--- a/crates/libafl_sugar/src/forkserver.rs
+++ b/crates/libafl_sugar/src/forkserver.rs
@@ -81,6 +81,9 @@ pub struct ForkserverBytesCoverageSugar<'a> {
/// Fuzz `iterations` number of times, instead of indefinitely; implies use of `fuzz_loop_for`
#[builder(default = None)]
iterations: Option,
+ /// Disable redirection of stdout to /dev/null on unix build targets
+ #[builder(default = None)]
+ enable_stdout: Option,
}
impl ForkserverBytesCoverageSugar<'_> {
@@ -337,11 +340,19 @@ impl ForkserverBytesCoverageSugar<'_> {
.remote_broker_addr(self.remote_broker_addr);
#[cfg(unix)]
- let launcher = launcher.stdout_file(Some("/dev/null"));
- match launcher.build().launch() {
- Ok(()) => (),
- Err(Error::ShuttingDown) => log::info!("\nFuzzing stopped by user. Good Bye."),
- Err(err) => panic!("Fuzzingg failed {err:?}"),
+ if self.enable_stdout.unwrap_or(false) {
+ match launcher.build().launch() {
+ Ok(()) => (),
+ Err(Error::ShuttingDown) => log::info!("\nFuzzing stopped by user. Good Bye."),
+ Err(err) => panic!("Fuzzingg failed {err:?}"),
+ }
+ } else {
+ let launcher = launcher.stdout_file(Some("/dev/null"));
+ match launcher.build().launch() {
+ Ok(()) => (),
+ Err(Error::ShuttingDown) => log::info!("\nFuzzing stopped by user. Good Bye."),
+ Err(err) => panic!("Fuzzingg failed {err:?}"),
+ }
}
}
}
@@ -367,6 +378,7 @@ pub mod pybind {
iterations: Option,
tokens_file: Option,
timeout: Option,
+ enable_stdout: Option,
}
#[pymethods]
@@ -380,7 +392,8 @@ pub mod pybind {
cores,
iterations=None,
tokens_file=None,
- timeout=None
+ timeout=None,
+ enable_stdout=None
))]
fn new(
input_dirs: Vec,
@@ -390,6 +403,7 @@ pub mod pybind {
iterations: Option,
tokens_file: Option,
timeout: Option,
+ enable_stdout: Option,
) -> Self {
Self {
input_dirs,
@@ -399,6 +413,7 @@ pub mod pybind {
iterations,
tokens_file,
timeout,
+ enable_stdout,
}
}
@@ -416,6 +431,7 @@ pub mod pybind {
.timeout(self.timeout)
.tokens_file(self.tokens_file.clone())
.iterations(self.iterations)
+ .enable_stdout(self.enable_stdout)
.build()
.run();
}
diff --git a/crates/libafl_sugar/src/qemu.rs b/crates/libafl_sugar/src/qemu.rs
index 63b8442302..4c7c4e21f4 100644
--- a/crates/libafl_sugar/src/qemu.rs
+++ b/crates/libafl_sugar/src/qemu.rs
@@ -40,7 +40,10 @@ use libafl_bolts::{
#[cfg(not(any(feature = "mips", feature = "hexagon")))]
use libafl_qemu::modules::CmpLogModule;
pub use libafl_qemu::qemu::Qemu;
-use libafl_qemu::{Emulator, QemuExecutor, modules::edges::StdEdgeCoverageModule};
+use libafl_qemu::{
+ Emulator, QemuExecutor,
+ modules::{SnapshotModule, edges::StdEdgeCoverageModule, utils::logic::OptionalModule},
+};
use libafl_targets::{CmpLogObserver, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND, edges_map_mut_ptr};
use typed_builder::TypedBuilder;
@@ -88,6 +91,8 @@ where
/// Disable redirection of stdout to /dev/null on unix build targets
#[builder(default = None)]
enable_stdout: Option,
+ #[builder(default = None)]
+ use_snapshot: Option,
}
impl Debug for QemuBytesCoverageSugar<'_, H>
@@ -115,6 +120,7 @@ where
)
.field("iterations", &self.iterations)
.field("enable_stdout", &self.enable_stdout)
+ .field("use_snapshot", &self.use_snapshot)
.finish()
}
}
@@ -234,6 +240,9 @@ where
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
+ let snap = SnapshotModule::new();
+ let snap = OptionalModule::new(self.use_snapshot.unwrap_or(false), snap);
+
// The wrapped harness function, calling out to the LLVM-style harness
if self.use_cmplog.unwrap_or(false) {
let modules = {
@@ -245,6 +254,7 @@ where
.build()
.unwrap(),
CmpLogModule::default(),
+ snap
)
}
#[cfg(any(feature = "mips", feature = "hexagon"))]
@@ -253,7 +263,8 @@ where
StdEdgeCoverageModule::builder()
.map_observer(edges_observer.as_mut())
.build()
- .unwrap()
+ .unwrap(),
+ snap
)
}
};
@@ -380,11 +391,14 @@ where
}
}
} else {
+ let snap = SnapshotModule::new();
+ let snap = OptionalModule::new(self.use_snapshot.unwrap_or(false), snap);
let modules = tuple_list!(
StdEdgeCoverageModule::builder()
.map_observer(edges_observer.as_mut())
.build()
- .unwrap()
+ .unwrap(),
+ snap
);
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _, _, _>,
@@ -549,6 +563,7 @@ pub mod pybind {
tokens_file: Option,
timeout: Option,
enable_stdout: Option,
+ use_snapshot: Option,
}
#[pymethods]
@@ -566,6 +581,7 @@ pub mod pybind {
tokens_file=None,
timeout=None,
enable_stdout=None,
+ use_snapshot=None,
))]
fn new(
input_dirs: Vec,
@@ -577,6 +593,7 @@ pub mod pybind {
tokens_file: Option,
timeout: Option,
enable_stdout: Option,
+ use_snapshot: Option,
) -> Self {
Self {
input_dirs,
@@ -588,6 +605,7 @@ pub mod pybind {
tokens_file,
timeout,
enable_stdout,
+ use_snapshot,
}
}
@@ -612,6 +630,7 @@ pub mod pybind {
.tokens_file(self.tokens_file.clone())
.iterations(self.iterations)
.enable_stdout(self.enable_stdout)
+ .use_snapshot(self.use_snapshot)
.build()
.run(QemuSugarParameter::Qemu(&qemu.qemu));
}