diff --git a/fuzzers/forkserver/libafl-fuzz/Cargo.toml b/fuzzers/forkserver/libafl-fuzz/Cargo.toml index 1a186b81acf..2d1b5a2841f 100644 --- a/fuzzers/forkserver/libafl-fuzz/Cargo.toml +++ b/fuzzers/forkserver/libafl-fuzz/Cargo.toml @@ -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"] diff --git a/fuzzers/forkserver/libafl-fuzz/Makefile.toml b/fuzzers/forkserver/libafl-fuzz/Makefile.toml index 5e77bbb15fe..520bc853a7c 100644 --- a/fuzzers/forkserver/libafl-fuzz/Makefile.toml +++ b/fuzzers/forkserver/libafl-fuzz/Makefile.toml @@ -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" diff --git a/fuzzers/forkserver/libafl-fuzz/src/executor.rs b/fuzzers/forkserver/libafl-fuzz/src/executor.rs index 90f49a9b578..42db166408e 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/executor.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/executor.rs @@ -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 { - Forkserver(FSV, PhantomData<(S, OT)>), - #[cfg(target_os = "linux")] + Forkserver(FSV, PhantomData<(S, OT, NYX)>), Nyx(NYX), } +#[cfg(feature = "nyx")] impl UsesState for SupportedExecutors where S: State, @@ -265,6 +266,7 @@ where type State = S; } +#[cfg(feature = "nyx")] impl Executor for SupportedExecutors where S: State, @@ -282,12 +284,13 @@ where ) -> Result { 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 HasObservers for SupportedExecutors where OT: ObserversTuple, @@ -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 HasTimeout for SupportedExecutors 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 UsesState for SupportedExecutors +where + S: State, +{ + type State = S; +} + +#[cfg(not(feature = "nyx"))] +pub enum SupportedExecutors { + Forkserver(FSV, PhantomData<(S, OT)>), +} + +#[cfg(not(feature = "nyx"))] +impl Executor for SupportedExecutors +where + S: State, + Z: UsesState, + EM: UsesState, + FSV: Executor, +{ + fn run_target( + &mut self, + fuzzer: &mut Z, + state: &mut S, + mgr: &mut EM, + input: &S::Input, + ) -> Result { + match self { + Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input), + } + } +} + +#[cfg(not(feature = "nyx"))] +impl HasObservers for SupportedExecutors +where + OT: ObserversTuple, + S: State, + FSV: HasObservers, +{ + 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 HasTimeout for SupportedExecutors +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(), + } + } +} diff --git a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs index d8d0f14b619..c985a81b0fc 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs @@ -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. diff --git a/fuzzers/forkserver/libafl-fuzz/src/main.rs b/fuzzers/forkserver/libafl-fuzz/src/main.rs index 0e37a5fe581..a5ae525e6f5 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/main.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/main.rs @@ -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)