From ba93e9d2ea9f36e697fa2d5bda1e22133c7fb4d5 Mon Sep 17 00:00:00 2001 From: lazymio Date: Sat, 17 May 2025 19:56:28 +0800 Subject: [PATCH] Add support for `AFL_LLVM/GCC_ONLY_FSRV` (#3245) * Add support for AFL_LLVM/GCC_ONLY_FSRV * clippy --- .../fuzzbench_forkserver_sand/src/main.rs | 1 + libafl/src/executors/forkserver.rs | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs b/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs index dc779ff768..a3b06f7ff0 100644 --- a/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs +++ b/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs @@ -388,6 +388,7 @@ fn fuzz( .shmem_provider(&mut shmem_provider) .parse_afl_cmdline(arguments) .coverage_map_size(MAP_SIZE) + .fsrv_only(true) .timeout(timeout) .kill_signal(signal) .is_persistent(true) diff --git a/libafl/src/executors/forkserver.rs b/libafl/src/executors/forkserver.rs index 54eeb2bfe4..4302f8531b 100644 --- a/libafl/src/executors/forkserver.rs +++ b/libafl/src/executors/forkserver.rs @@ -159,6 +159,12 @@ pub const SHM_CMPLOG_ENV_VAR: &str = "__AFL_CMPLOG_SHM_ID"; /// Environment variable key for a custom AFL coverage map size pub const AFL_MAP_SIZE_ENV_VAR: &str = "AFL_MAP_SIZE"; +/// Environment variable keys to skip instrumentation (LLVM variant). +pub const AFL_LLVM_ONLY_FSRV_VAR: &str = "AFL_LLVM_ONLY_FSRV"; + +/// Environment variable keys to skip instrumentation (GCC variant). +pub const AFL_GCC_ONLY_FSRV_VAR: &str = "AFL_GCC_ONLY_FSRV"; + /// The default signal to use to kill child processes const KILL_SIGNAL_DEFAULT: Signal = Signal::SIGTERM; @@ -374,6 +380,7 @@ impl Forkserver { memlimit: u64, is_persistent: bool, is_deferred_frksrv: bool, + is_fsrv_only: bool, dump_asan_logs: bool, coverage_map_size: Option, debug_output: bool, @@ -453,6 +460,11 @@ impl Forkserver { command.env("__AFL_DEFER_FORKSRV", "1"); } + if is_fsrv_only { + command.env(AFL_GCC_ONLY_FSRV_VAR, "1"); + command.env(AFL_LLVM_ONLY_FSRV_VAR, "1"); + } + #[cfg(feature = "regex")] { let asan_options = if dump_asan_logs { @@ -844,12 +856,14 @@ where /// The builder for `ForkserverExecutor` #[derive(Debug)] +#[expect(clippy::struct_excessive_bools)] pub struct ForkserverExecutorBuilder<'a, SP> { target_inner: StdTargetArgsInner, child_env_inner: StdChildArgsInner, uses_shmem_testcase: bool, is_persistent: bool, is_deferred_frksrv: bool, + is_fsrv_only: bool, autotokens: Option<&'a mut Tokens>, shmem_provider: Option<&'a mut SP>, max_input_size: usize, @@ -1058,6 +1072,7 @@ where 0, self.is_persistent, self.is_deferred_frksrv, + self.is_fsrv_only, self.has_asan_obs(), self.map_size, self.child_env_inner.debug_child, @@ -1316,6 +1331,14 @@ where Ok(actual_map_size as usize) } + #[must_use] + /// If set to true, we will only spin up a forkserver without any coverage collected. This is useful for several + /// scenario like slave executors of SAND or cmplog executors. + pub fn fsrv_only(mut self, fsrv_only: bool) -> Self { + self.is_fsrv_only = fsrv_only; + self + } + /// Use autodict? #[must_use] pub fn autotokens(mut self, tokens: &'a mut Tokens) -> Self { @@ -1402,6 +1425,7 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> { uses_shmem_testcase: false, is_persistent: false, is_deferred_frksrv: false, + is_fsrv_only: false, autotokens: None, shmem_provider: None, map_size: None, @@ -1430,6 +1454,7 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> { uses_shmem_testcase: self.uses_shmem_testcase, is_persistent: self.is_persistent, is_deferred_frksrv: self.is_deferred_frksrv, + is_fsrv_only: self.is_fsrv_only, autotokens: self.autotokens, map_size: self.map_size, max_input_size: self.max_input_size,