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"] }
|
nix = { version = "0.29.0", features = ["fs"] }
|
||||||
regex = "1.10.5"
|
regex = "1.10.5"
|
||||||
serde = { version = "1.0.117", features = ["derive"] }
|
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]
|
[features]
|
||||||
default = ["track_hit_feedbacks"]
|
default = ["track_hit_feedbacks"]
|
||||||
track_hit_feedbacks = ["libafl/track_hit_feedbacks"]
|
track_hit_feedbacks = ["libafl/track_hit_feedbacks"]
|
||||||
fuzzbench = []
|
fuzzbench = []
|
||||||
|
nyx = ["dep:libafl_nyx"]
|
||||||
|
@ -69,6 +69,9 @@ dependencies = [
|
|||||||
"test_frida",
|
"test_frida",
|
||||||
"test_qemu",
|
"test_qemu",
|
||||||
"test_unicorn_mode",
|
"test_unicorn_mode",
|
||||||
|
# nyx
|
||||||
|
# since we cannot test nyx mode on CI, let's build it
|
||||||
|
"build_nyx_mode",
|
||||||
# fuzzbench
|
# fuzzbench
|
||||||
"test_instr_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"]
|
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]
|
[tasks.clean]
|
||||||
linux_alias = "clean_unix"
|
linux_alias = "clean_unix"
|
||||||
mac_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 {
|
} else {
|
||||||
bin_path = &opt.executable;
|
bin_path = &opt.executable;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "nyx")]
|
||||||
{
|
{
|
||||||
if opt.nyx_mode {
|
if opt.nyx_mode {
|
||||||
if !bin_path.is_symlink() && bin_path.is_dir() {
|
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
|
// check if the binary is an ELF file
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "nyx")]
|
||||||
if mmap[0..4] != [0x7f, 0x45, 0x4c, 0x46] {
|
if mmap[0..4] != [0x7f, 0x45, 0x4c, 0x46] {
|
||||||
return Err(Error::illegal_argument(format!(
|
return Err(Error::illegal_argument(format!(
|
||||||
"Program '{}' is not an ELF binary",
|
"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.forkserver_cs
|
||||||
&& !opt.non_instrumented_mode;
|
&& !opt.non_instrumented_mode;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "nyx")]
|
||||||
let check_instrumentation = check_instrumentation && !opt.nyx_mode;
|
let check_instrumentation = check_instrumentation && !opt.nyx_mode;
|
||||||
|
|
||||||
if check_instrumentation && !is_instrumented(&mmap, shmem_env_var) {
|
if check_instrumentation && !is_instrumented(&mmap, shmem_env_var) {
|
||||||
@ -252,12 +252,13 @@ fn check_file_found(file: &Path, perm: u32) -> bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "nyx")]
|
||||||
pub enum SupportedExecutors<S, OT, FSV, NYX> {
|
pub enum SupportedExecutors<S, OT, FSV, NYX> {
|
||||||
Forkserver(FSV, PhantomData<(S, OT)>),
|
Forkserver(FSV, PhantomData<(S, OT, NYX)>),
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
Nyx(NYX),
|
Nyx(NYX),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "nyx")]
|
||||||
impl<S, OT, FSV, NYX> UsesState for SupportedExecutors<S, OT, FSV, NYX>
|
impl<S, OT, FSV, NYX> UsesState for SupportedExecutors<S, OT, FSV, NYX>
|
||||||
where
|
where
|
||||||
S: State,
|
S: State,
|
||||||
@ -265,6 +266,7 @@ where
|
|||||||
type State = S;
|
type State = S;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "nyx")]
|
||||||
impl<S, OT, FSV, NYX, EM, Z> Executor<EM, Z> for SupportedExecutors<S, OT, FSV, NYX>
|
impl<S, OT, FSV, NYX, EM, Z> Executor<EM, Z> for SupportedExecutors<S, OT, FSV, NYX>
|
||||||
where
|
where
|
||||||
S: State,
|
S: State,
|
||||||
@ -282,12 +284,13 @@ where
|
|||||||
) -> Result<ExitKind, Error> {
|
) -> Result<ExitKind, Error> {
|
||||||
match self {
|
match self {
|
||||||
Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input),
|
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),
|
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>
|
impl<S, OT, FSV, NYX> HasObservers for SupportedExecutors<S, OT, FSV, NYX>
|
||||||
where
|
where
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
@ -300,7 +303,7 @@ where
|
|||||||
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
|
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
|
||||||
match self {
|
match self {
|
||||||
Self::Forkserver(fsrv, _) => fsrv.observers(),
|
Self::Forkserver(fsrv, _) => fsrv.observers(),
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "nyx")]
|
||||||
Self::Nyx(nyx) => nyx.observers(),
|
Self::Nyx(nyx) => nyx.observers(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,12 +312,13 @@ where
|
|||||||
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
|
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
|
||||||
match self {
|
match self {
|
||||||
Self::Forkserver(fsrv, _) => fsrv.observers_mut(),
|
Self::Forkserver(fsrv, _) => fsrv.observers_mut(),
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "nyx")]
|
||||||
Self::Nyx(nyx) => nyx.observers_mut(),
|
Self::Nyx(nyx) => nyx.observers_mut(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "nyx")]
|
||||||
impl<S, OT, FSV, NYX> HasTimeout for SupportedExecutors<S, OT, FSV, NYX>
|
impl<S, OT, FSV, NYX> HasTimeout for SupportedExecutors<S, OT, FSV, NYX>
|
||||||
where
|
where
|
||||||
FSV: HasTimeout,
|
FSV: HasTimeout,
|
||||||
@ -323,15 +327,89 @@ where
|
|||||||
fn set_timeout(&mut self, timeout: std::time::Duration) {
|
fn set_timeout(&mut self, timeout: std::time::Duration) {
|
||||||
match self {
|
match self {
|
||||||
Self::Forkserver(fsrv, _) => fsrv.set_timeout(timeout),
|
Self::Forkserver(fsrv, _) => fsrv.set_timeout(timeout),
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "nyx")]
|
||||||
Self::Nyx(nyx) => nyx.set_timeout(timeout),
|
Self::Nyx(nyx) => nyx.set_timeout(timeout),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn timeout(&self) -> std::time::Duration {
|
fn timeout(&self) -> std::time::Duration {
|
||||||
match self {
|
match self {
|
||||||
Self::Forkserver(fsrv, _) => fsrv.timeout(),
|
Self::Forkserver(fsrv, _) => fsrv.timeout(),
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "nyx")]
|
||||||
Self::Nyx(nyx) => nyx.timeout(),
|
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},
|
tuples::{tuple_list, Handled, Merge},
|
||||||
AsSliceMut,
|
AsSliceMut,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "nyx")]
|
||||||
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper, settings::NyxSettings};
|
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper, settings::NyxSettings};
|
||||||
use libafl_targets::{cmps::AFLppCmpLogMap, AFLppCmpLogObserver, AFLppCmplogTracingStage};
|
use libafl_targets::{cmps::AFLppCmpLogMap, AFLppCmpLogObserver, AFLppCmplogTracingStage};
|
||||||
use serde::{Deserialize, Serialize};
|
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();
|
let shmem_buf = shmem.as_slice_mut();
|
||||||
|
|
||||||
// If we are in Nyx Mode, we need to use a different map observer.
|
// 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) = {
|
let (nyx_helper, edges_observer) = {
|
||||||
if opt.nyx_mode {
|
if opt.nyx_mode {
|
||||||
// main node is the first core id in CentralizedLauncher
|
// 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)
|
(None, observer)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(feature = "nyx"))]
|
||||||
let edges_observer = { unsafe { StdMapObserver::new("edges", shmem_buf) } };
|
let edges_observer = { unsafe { StdMapObserver::new("edges", shmem_buf) } };
|
||||||
|
|
||||||
let edges_observer = HitcountsMapObserver::new(edges_observer).track_indices();
|
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("LD_PRELOAD", &preload);
|
||||||
std::env::set_var("DYLD_INSERT_LIBRARIES", &preload);
|
std::env::set_var("DYLD_INSERT_LIBRARIES", &preload);
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "nyx")]
|
||||||
let mut executor = {
|
let mut executor = {
|
||||||
if opt.nyx_mode {
|
if opt.nyx_mode {
|
||||||
SupportedExecutors::Nyx(NyxExecutor::builder().build(
|
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"))]
|
#[cfg(not(feature = "nyx"))]
|
||||||
let executor = {
|
let mut executor = {
|
||||||
// Create the base Executor
|
// Create the base Executor
|
||||||
let mut executor_builder = base_forkserver_builder(opt, &mut shmem_provider, fuzzer_dir);
|
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.
|
// 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)
|
/// use binary-only instrumentation (QEMU mode)
|
||||||
#[arg(short = 'Q')]
|
#[arg(short = 'Q')]
|
||||||
qemu_mode: bool,
|
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')]
|
#[arg(short = 'X')]
|
||||||
nyx_mode: bool,
|
nyx_mode: bool,
|
||||||
/// use unicorn-based instrumentation (Unicorn mode)
|
/// use unicorn-based instrumentation (Unicorn mode)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user