libafl-fuzz: feature-flag nyx mode (#2712)
This commit is contained in:
parent
e7f48889e7
commit
6e707d15bb
@ -31,9 +31,12 @@ memmap2 = "0.9.4"
|
||||
nix = { version = "0.29.0", features = ["fs"] }
|
||||
regex = "1.10.5"
|
||||
serde = { version = "1.0.117", features = ["derive"] }
|
||||
libafl_nyx = { path = "../../../libafl_nyx" }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
libafl_nyx = { path = "../../../libafl_nyx", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["track_hit_feedbacks"]
|
||||
track_hit_feedbacks = ["libafl/track_hit_feedbacks"]
|
||||
fuzzbench = []
|
||||
nyx = ["dep:libafl_nyx"]
|
||||
|
@ -69,6 +69,9 @@ dependencies = [
|
||||
"test_frida",
|
||||
"test_qemu",
|
||||
"test_unicorn_mode",
|
||||
# nyx
|
||||
# since we cannot test nyx mode on CI, let's build it
|
||||
"build_nyx_mode",
|
||||
# fuzzbench
|
||||
"test_instr_fuzzbench",
|
||||
]
|
||||
@ -295,6 +298,11 @@ test -n "$( ls ./test/output-nyx/fuzzer_main/queue/id:000003* 2>/dev/null )" ||
|
||||
'''
|
||||
dependencies = ["build_afl", "build_libafl_fuzz"]
|
||||
|
||||
# since we cannot test nyx mode on CI, let's build it
|
||||
[tasks.build_nyx_mode]
|
||||
script_runner = "@shell"
|
||||
script = "cargo build --profile ${PROFILE} --features nyx"
|
||||
|
||||
[tasks.clean]
|
||||
linux_alias = "clean_unix"
|
||||
mac_alias = "clean_unix"
|
||||
|
@ -39,7 +39,7 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> {
|
||||
}
|
||||
} else {
|
||||
bin_path = &opt.executable;
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "nyx")]
|
||||
{
|
||||
if opt.nyx_mode {
|
||||
if !bin_path.is_symlink() && bin_path.is_dir() {
|
||||
@ -91,7 +91,7 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> {
|
||||
}
|
||||
|
||||
// check if the binary is an ELF file
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "nyx")]
|
||||
if mmap[0..4] != [0x7f, 0x45, 0x4c, 0x46] {
|
||||
return Err(Error::illegal_argument(format!(
|
||||
"Program '{}' is not an ELF binary",
|
||||
@ -117,7 +117,7 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> {
|
||||
&& !opt.forkserver_cs
|
||||
&& !opt.non_instrumented_mode;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "nyx")]
|
||||
let check_instrumentation = check_instrumentation && !opt.nyx_mode;
|
||||
|
||||
if check_instrumentation && !is_instrumented(&mmap, shmem_env_var) {
|
||||
@ -252,12 +252,13 @@ fn check_file_found(file: &Path, perm: u32) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(feature = "nyx")]
|
||||
pub enum SupportedExecutors<S, OT, FSV, NYX> {
|
||||
Forkserver(FSV, PhantomData<(S, OT)>),
|
||||
#[cfg(target_os = "linux")]
|
||||
Forkserver(FSV, PhantomData<(S, OT, NYX)>),
|
||||
Nyx(NYX),
|
||||
}
|
||||
|
||||
#[cfg(feature = "nyx")]
|
||||
impl<S, OT, FSV, NYX> UsesState for SupportedExecutors<S, OT, FSV, NYX>
|
||||
where
|
||||
S: State,
|
||||
@ -265,6 +266,7 @@ where
|
||||
type State = S;
|
||||
}
|
||||
|
||||
#[cfg(feature = "nyx")]
|
||||
impl<S, OT, FSV, NYX, EM, Z> Executor<EM, Z> for SupportedExecutors<S, OT, FSV, NYX>
|
||||
where
|
||||
S: State,
|
||||
@ -282,12 +284,13 @@ where
|
||||
) -> Result<ExitKind, Error> {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "nyx")]
|
||||
Self::Nyx(nyx) => nyx.run_target(fuzzer, state, mgr, input),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nyx")]
|
||||
impl<S, OT, FSV, NYX> HasObservers for SupportedExecutors<S, OT, FSV, NYX>
|
||||
where
|
||||
OT: ObserversTuple<S::Input, S>,
|
||||
@ -300,7 +303,7 @@ where
|
||||
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.observers(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "nyx")]
|
||||
Self::Nyx(nyx) => nyx.observers(),
|
||||
}
|
||||
}
|
||||
@ -309,12 +312,13 @@ where
|
||||
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.observers_mut(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "nyx")]
|
||||
Self::Nyx(nyx) => nyx.observers_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nyx")]
|
||||
impl<S, OT, FSV, NYX> HasTimeout for SupportedExecutors<S, OT, FSV, NYX>
|
||||
where
|
||||
FSV: HasTimeout,
|
||||
@ -323,15 +327,89 @@ where
|
||||
fn set_timeout(&mut self, timeout: std::time::Duration) {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.set_timeout(timeout),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "nyx")]
|
||||
Self::Nyx(nyx) => nyx.set_timeout(timeout),
|
||||
}
|
||||
}
|
||||
fn timeout(&self) -> std::time::Duration {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.timeout(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "nyx")]
|
||||
Self::Nyx(nyx) => nyx.timeout(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nyx"))]
|
||||
impl<S, OT, FSV> UsesState for SupportedExecutors<S, OT, FSV>
|
||||
where
|
||||
S: State,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nyx"))]
|
||||
pub enum SupportedExecutors<S, OT, FSV> {
|
||||
Forkserver(FSV, PhantomData<(S, OT)>),
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nyx"))]
|
||||
impl<S, OT, FSV, EM, Z> Executor<EM, Z> for SupportedExecutors<S, OT, FSV>
|
||||
where
|
||||
S: State,
|
||||
Z: UsesState<State = S>,
|
||||
EM: UsesState<State = S>,
|
||||
FSV: Executor<EM, Z, State = S>,
|
||||
{
|
||||
fn run_target(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
mgr: &mut EM,
|
||||
input: &S::Input,
|
||||
) -> Result<ExitKind, Error> {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nyx"))]
|
||||
impl<S, OT, FSV> HasObservers for SupportedExecutors<S, OT, FSV>
|
||||
where
|
||||
OT: ObserversTuple<S::Input, S>,
|
||||
S: State,
|
||||
FSV: HasObservers<Observers = OT>,
|
||||
{
|
||||
type Observers = OT;
|
||||
#[inline]
|
||||
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.observers(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.observers_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nyx"))]
|
||||
impl<S, OT, FSV> HasTimeout for SupportedExecutors<S, OT, FSV>
|
||||
where
|
||||
FSV: HasTimeout,
|
||||
{
|
||||
fn set_timeout(&mut self, timeout: std::time::Duration) {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.set_timeout(timeout),
|
||||
}
|
||||
}
|
||||
fn timeout(&self) -> std::time::Duration {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.timeout(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ use libafl_bolts::{
|
||||
tuples::{tuple_list, Handled, Merge},
|
||||
AsSliceMut,
|
||||
};
|
||||
#[cfg(feature = "nyx")]
|
||||
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper, settings::NyxSettings};
|
||||
use libafl_targets::{cmps::AFLppCmpLogMap, AFLppCmpLogObserver, AFLppCmplogTracingStage};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -125,7 +126,7 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
|
||||
let shmem_buf = shmem.as_slice_mut();
|
||||
|
||||
// If we are in Nyx Mode, we need to use a different map observer.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "nyx")]
|
||||
let (nyx_helper, edges_observer) = {
|
||||
if opt.nyx_mode {
|
||||
// main node is the first core id in CentralizedLauncher
|
||||
@ -152,7 +153,7 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
|
||||
(None, observer)
|
||||
}
|
||||
};
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[cfg(not(feature = "nyx"))]
|
||||
let edges_observer = { unsafe { StdMapObserver::new("edges", shmem_buf) } };
|
||||
|
||||
let edges_observer = HitcountsMapObserver::new(edges_observer).track_indices();
|
||||
@ -319,7 +320,7 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
|
||||
std::env::set_var("LD_PRELOAD", &preload);
|
||||
std::env::set_var("DYLD_INSERT_LIBRARIES", &preload);
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(feature = "nyx")]
|
||||
let mut executor = {
|
||||
if opt.nyx_mode {
|
||||
SupportedExecutors::Nyx(NyxExecutor::builder().build(
|
||||
@ -349,8 +350,8 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
|
||||
)
|
||||
}
|
||||
};
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let executor = {
|
||||
#[cfg(not(feature = "nyx"))]
|
||||
let mut executor = {
|
||||
// Create the base Executor
|
||||
let mut executor_builder = base_forkserver_builder(opt, &mut shmem_provider, fuzzer_dir);
|
||||
// Set a custom exit code to be interpreted as a Crash if configured.
|
||||
|
@ -313,7 +313,8 @@ struct Opt {
|
||||
/// use binary-only instrumentation (QEMU mode)
|
||||
#[arg(short = 'Q')]
|
||||
qemu_mode: bool,
|
||||
#[cfg(target_os = "linux")]
|
||||
/// Nyx mode (Note: unlike AFL++, you do not need to specify -Y for parallel nyx fuzzing)
|
||||
#[cfg(feature = "nyx")]
|
||||
#[arg(short = 'X')]
|
||||
nyx_mode: bool,
|
||||
/// use unicorn-based instrumentation (Unicorn mode)
|
||||
|
Loading…
x
Reference in New Issue
Block a user