Skip to content

Commit 52d5aa9

Browse files
R9295riesentoaster
authored andcommitted
libafl-fuzz: feature-flag nyx mode (AFLplusplus#2712)
1 parent 5d523b9 commit 52d5aa9

File tree

5 files changed

+108
-17
lines changed

5 files changed

+108
-17
lines changed

fuzzers/forkserver/libafl-fuzz/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ memmap2 = "0.9.4"
3131
nix = { version = "0.29.0", features = ["fs"] }
3232
regex = "1.10.5"
3333
serde = { version = "1.0.117", features = ["derive"] }
34-
libafl_nyx = { path = "../../../libafl_nyx" }
34+
35+
[target.'cfg(target_os = "linux")'.dependencies]
36+
libafl_nyx = { path = "../../../libafl_nyx", optional = true }
3537

3638
[features]
3739
default = ["track_hit_feedbacks"]
3840
track_hit_feedbacks = ["libafl/track_hit_feedbacks"]
3941
fuzzbench = []
42+
nyx = ["dep:libafl_nyx"]

fuzzers/forkserver/libafl-fuzz/Makefile.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ dependencies = [
6969
"test_frida",
7070
"test_qemu",
7171
"test_unicorn_mode",
72+
# nyx
73+
# since we cannot test nyx mode on CI, let's build it
74+
"build_nyx_mode",
7275
# fuzzbench
7376
"test_instr_fuzzbench",
7477
]
@@ -295,6 +298,11 @@ test -n "$( ls ./test/output-nyx/fuzzer_main/queue/id:000003* 2>/dev/null )" ||
295298
'''
296299
dependencies = ["build_afl", "build_libafl_fuzz"]
297300

301+
# since we cannot test nyx mode on CI, let's build it
302+
[tasks.build_nyx_mode]
303+
script_runner = "@shell"
304+
script = "cargo build --profile ${PROFILE} --features nyx"
305+
298306
[tasks.clean]
299307
linux_alias = "clean_unix"
300308
mac_alias = "clean_unix"

fuzzers/forkserver/libafl-fuzz/src/executor.rs

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> {
3939
}
4040
} else {
4141
bin_path = &opt.executable;
42-
#[cfg(target_os = "linux")]
42+
#[cfg(feature = "nyx")]
4343
{
4444
if opt.nyx_mode {
4545
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> {
9191
}
9292

9393
// check if the binary is an ELF file
94-
#[cfg(target_os = "linux")]
94+
#[cfg(feature = "nyx")]
9595
if mmap[0..4] != [0x7f, 0x45, 0x4c, 0x46] {
9696
return Err(Error::illegal_argument(format!(
9797
"Program '{}' is not an ELF binary",
@@ -117,7 +117,7 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> {
117117
&& !opt.forkserver_cs
118118
&& !opt.non_instrumented_mode;
119119

120-
#[cfg(target_os = "linux")]
120+
#[cfg(feature = "nyx")]
121121
let check_instrumentation = check_instrumentation && !opt.nyx_mode;
122122

123123
if check_instrumentation && !is_instrumented(&mmap, shmem_env_var) {
@@ -252,19 +252,21 @@ fn check_file_found(file: &Path, perm: u32) -> bool {
252252
false
253253
}
254254

255+
#[cfg(feature = "nyx")]
255256
pub enum SupportedExecutors<S, OT, FSV, NYX> {
256-
Forkserver(FSV, PhantomData<(S, OT)>),
257-
#[cfg(target_os = "linux")]
257+
Forkserver(FSV, PhantomData<(S, OT, NYX)>),
258258
Nyx(NYX),
259259
}
260260

261+
#[cfg(feature = "nyx")]
261262
impl<S, OT, FSV, NYX> UsesState for SupportedExecutors<S, OT, FSV, NYX>
262263
where
263264
S: State,
264265
{
265266
type State = S;
266267
}
267268

269+
#[cfg(feature = "nyx")]
268270
impl<S, OT, FSV, NYX, EM, Z> Executor<EM, Z> for SupportedExecutors<S, OT, FSV, NYX>
269271
where
270272
S: State,
@@ -282,12 +284,13 @@ where
282284
) -> Result<ExitKind, Error> {
283285
match self {
284286
Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input),
285-
#[cfg(target_os = "linux")]
287+
#[cfg(feature = "nyx")]
286288
Self::Nyx(nyx) => nyx.run_target(fuzzer, state, mgr, input),
287289
}
288290
}
289291
}
290292

293+
#[cfg(feature = "nyx")]
291294
impl<S, OT, FSV, NYX> HasObservers for SupportedExecutors<S, OT, FSV, NYX>
292295
where
293296
OT: ObserversTuple<S::Input, S>,
@@ -300,7 +303,7 @@ where
300303
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
301304
match self {
302305
Self::Forkserver(fsrv, _) => fsrv.observers(),
303-
#[cfg(target_os = "linux")]
306+
#[cfg(feature = "nyx")]
304307
Self::Nyx(nyx) => nyx.observers(),
305308
}
306309
}
@@ -309,12 +312,13 @@ where
309312
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
310313
match self {
311314
Self::Forkserver(fsrv, _) => fsrv.observers_mut(),
312-
#[cfg(target_os = "linux")]
315+
#[cfg(feature = "nyx")]
313316
Self::Nyx(nyx) => nyx.observers_mut(),
314317
}
315318
}
316319
}
317320

321+
#[cfg(feature = "nyx")]
318322
impl<S, OT, FSV, NYX> HasTimeout for SupportedExecutors<S, OT, FSV, NYX>
319323
where
320324
FSV: HasTimeout,
@@ -323,15 +327,89 @@ where
323327
fn set_timeout(&mut self, timeout: std::time::Duration) {
324328
match self {
325329
Self::Forkserver(fsrv, _) => fsrv.set_timeout(timeout),
326-
#[cfg(target_os = "linux")]
330+
#[cfg(feature = "nyx")]
327331
Self::Nyx(nyx) => nyx.set_timeout(timeout),
328332
}
329333
}
330334
fn timeout(&self) -> std::time::Duration {
331335
match self {
332336
Self::Forkserver(fsrv, _) => fsrv.timeout(),
333-
#[cfg(target_os = "linux")]
337+
#[cfg(feature = "nyx")]
334338
Self::Nyx(nyx) => nyx.timeout(),
335339
}
336340
}
337341
}
342+
343+
#[cfg(not(feature = "nyx"))]
344+
impl<S, OT, FSV> UsesState for SupportedExecutors<S, OT, FSV>
345+
where
346+
S: State,
347+
{
348+
type State = S;
349+
}
350+
351+
#[cfg(not(feature = "nyx"))]
352+
pub enum SupportedExecutors<S, OT, FSV> {
353+
Forkserver(FSV, PhantomData<(S, OT)>),
354+
}
355+
356+
#[cfg(not(feature = "nyx"))]
357+
impl<S, OT, FSV, EM, Z> Executor<EM, Z> for SupportedExecutors<S, OT, FSV>
358+
where
359+
S: State,
360+
Z: UsesState<State = S>,
361+
EM: UsesState<State = S>,
362+
FSV: Executor<EM, Z, State = S>,
363+
{
364+
fn run_target(
365+
&mut self,
366+
fuzzer: &mut Z,
367+
state: &mut S,
368+
mgr: &mut EM,
369+
input: &S::Input,
370+
) -> Result<ExitKind, Error> {
371+
match self {
372+
Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input),
373+
}
374+
}
375+
}
376+
377+
#[cfg(not(feature = "nyx"))]
378+
impl<S, OT, FSV> HasObservers for SupportedExecutors<S, OT, FSV>
379+
where
380+
OT: ObserversTuple<S::Input, S>,
381+
S: State,
382+
FSV: HasObservers<Observers = OT>,
383+
{
384+
type Observers = OT;
385+
#[inline]
386+
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
387+
match self {
388+
Self::Forkserver(fsrv, _) => fsrv.observers(),
389+
}
390+
}
391+
392+
#[inline]
393+
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
394+
match self {
395+
Self::Forkserver(fsrv, _) => fsrv.observers_mut(),
396+
}
397+
}
398+
}
399+
400+
#[cfg(not(feature = "nyx"))]
401+
impl<S, OT, FSV> HasTimeout for SupportedExecutors<S, OT, FSV>
402+
where
403+
FSV: HasTimeout,
404+
{
405+
fn set_timeout(&mut self, timeout: std::time::Duration) {
406+
match self {
407+
Self::Forkserver(fsrv, _) => fsrv.set_timeout(timeout),
408+
}
409+
}
410+
fn timeout(&self) -> std::time::Duration {
411+
match self {
412+
Self::Forkserver(fsrv, _) => fsrv.timeout(),
413+
}
414+
}
415+
}

fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ use libafl_bolts::{
5454
tuples::{tuple_list, Handled, Merge},
5555
AsSliceMut,
5656
};
57+
#[cfg(feature = "nyx")]
5758
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper, settings::NyxSettings};
5859
use libafl_targets::{cmps::AFLppCmpLogMap, AFLppCmpLogObserver, AFLppCmplogTracingStage};
5960
use serde::{Deserialize, Serialize};
@@ -125,7 +126,7 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
125126
let shmem_buf = shmem.as_slice_mut();
126127

127128
// If we are in Nyx Mode, we need to use a different map observer.
128-
#[cfg(target_os = "linux")]
129+
#[cfg(feature = "nyx")]
129130
let (nyx_helper, edges_observer) = {
130131
if opt.nyx_mode {
131132
// 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, {
152153
(None, observer)
153154
}
154155
};
155-
#[cfg(not(target_os = "linux"))]
156+
#[cfg(not(feature = "nyx"))]
156157
let edges_observer = { unsafe { StdMapObserver::new("edges", shmem_buf) } };
157158

158159
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, {
319320
std::env::set_var("LD_PRELOAD", &preload);
320321
std::env::set_var("DYLD_INSERT_LIBRARIES", &preload);
321322
}
322-
#[cfg(target_os = "linux")]
323+
#[cfg(feature = "nyx")]
323324
let mut executor = {
324325
if opt.nyx_mode {
325326
SupportedExecutors::Nyx(NyxExecutor::builder().build(
@@ -349,8 +350,8 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
349350
)
350351
}
351352
};
352-
#[cfg(not(target_os = "linux"))]
353-
let executor = {
353+
#[cfg(not(feature = "nyx"))]
354+
let mut executor = {
354355
// Create the base Executor
355356
let mut executor_builder = base_forkserver_builder(opt, &mut shmem_provider, fuzzer_dir);
356357
// Set a custom exit code to be interpreted as a Crash if configured.

fuzzers/forkserver/libafl-fuzz/src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,8 @@ struct Opt {
313313
/// use binary-only instrumentation (QEMU mode)
314314
#[arg(short = 'Q')]
315315
qemu_mode: bool,
316-
#[cfg(target_os = "linux")]
316+
/// Nyx mode (Note: unlike AFL++, you do not need to specify -Y for parallel nyx fuzzing)
317+
#[cfg(feature = "nyx")]
317318
#[arg(short = 'X')]
318319
nyx_mode: bool,
319320
/// use unicorn-based instrumentation (Unicorn mode)

0 commit comments

Comments
 (0)