From 6dd52722de1291239b9d1b5c4198819d8d4931ae Mon Sep 17 00:00:00 2001 From: EvianZhang Date: Wed, 7 May 2025 16:44:44 +0800 Subject: [PATCH] Add cmplog shared memory mapping method for forkserver (#3200) --- .../fuzzbench_forkserver/src/main.rs | 4 +- .../fuzzbench_forkserver_cmplog/src/main.rs | 4 +- .../fuzzbench_forkserver_sand/src/main.rs | 7 ++- fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs | 4 +- libafl/src/executors/forkserver.rs | 2 + libafl_targets/src/forkserver.rs | 44 ++++++++++++++++++- 6 files changed, 56 insertions(+), 9 deletions(-) diff --git a/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs b/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs index 44667a43e5..d458def788 100644 --- a/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs +++ b/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs @@ -11,7 +11,7 @@ use clap::{Arg, ArgAction, Command}; use libafl::{ corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus}, events::SimpleEventManager, - executors::forkserver::ForkserverExecutor, + executors::forkserver::{ForkserverExecutor, SHM_CMPLOG_ENV_VAR}, feedback_or, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, @@ -351,7 +351,7 @@ fn fuzz( let mut cmplog_shmem = shmem_provider.uninit_on_shmem::().unwrap(); // let the forkserver know the shmid unsafe { - cmplog_shmem.write_to_env("__AFL_CMPLOG_SHM_ID").unwrap(); + cmplog_shmem.write_to_env(SHM_CMPLOG_ENV_VAR).unwrap(); } let cmpmap = unsafe { OwnedRefMut::::from_shmem(&mut cmplog_shmem) }; diff --git a/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs b/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs index dd76c995d9..cbde2ba326 100644 --- a/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs +++ b/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs @@ -11,7 +11,7 @@ use clap::{Arg, ArgAction, Command}; use libafl::{ corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus}, events::SimpleEventManager, - executors::forkserver::ForkserverExecutor, + executors::forkserver::{ForkserverExecutor, SHM_CMPLOG_ENV_VAR}, feedback_or, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, @@ -354,7 +354,7 @@ fn fuzz( let mut cmplog_shmem = shmem_provider.uninit_on_shmem::().unwrap(); // let the forkserver know the shmid unsafe { - cmplog_shmem.write_to_env("__AFL_CMPLOG_SHM_ID").unwrap(); + cmplog_shmem.write_to_env(SHM_CMPLOG_ENV_VAR).unwrap(); } let cmpmap = unsafe { OwnedRefMut::from_shmem(&mut cmplog_shmem) }; diff --git a/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs b/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs index a9585133ac..93393dfbf0 100644 --- a/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs +++ b/fuzzers/forkserver/fuzzbench_forkserver_sand/src/main.rs @@ -11,7 +11,10 @@ use clap::{Arg, ArgAction, Command}; use libafl::{ corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus}, events::SimpleEventManager, - executors::{forkserver::ForkserverExecutor, sand::SANDExecutor}, + executors::{ + forkserver::{ForkserverExecutor, SHM_CMPLOG_ENV_VAR}, + sand::SANDExecutor, + }, feedback_or, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, @@ -398,7 +401,7 @@ fn fuzz( let mut cmplog_shmem = shmem_provider.uninit_on_shmem::().unwrap(); // let the forkserver know the shmid unsafe { - cmplog_shmem.write_to_env("__AFL_CMPLOG_SHM_ID").unwrap(); + cmplog_shmem.write_to_env(SHM_CMPLOG_ENV_VAR).unwrap(); } let cmpmap = unsafe { OwnedRefMut::::from_shmem(&mut cmplog_shmem) }; diff --git a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs index ef265a3c3e..7ae2402e00 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs @@ -16,7 +16,7 @@ use libafl::monitors::SimpleMonitor; use libafl::{ corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus}, events::ProgressReporter, - executors::forkserver::{ForkserverExecutor, ForkserverExecutorBuilder}, + executors::forkserver::{ForkserverExecutor, ForkserverExecutorBuilder, SHM_CMPLOG_ENV_VAR}, feedback_and, feedback_or, feedback_or_fast, feedbacks::{ CaptureTimeoutFeedback, ConstFeedback, CrashFeedback, MaxMapFeedback, TimeFeedback, @@ -476,7 +476,7 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, { // Let the Forkserver know the CmpLog shared memory map ID. unsafe { - cmplog_shmem.write_to_env("__AFL_CMPLOG_SHM_ID").unwrap(); + cmplog_shmem.write_to_env(SHM_CMPLOG_ENV_VAR).unwrap(); } let cmpmap = unsafe { OwnedRefMut::from_shmem(&mut cmplog_shmem) }; diff --git a/libafl/src/executors/forkserver.rs b/libafl/src/executors/forkserver.rs index 7144fceaf1..d4d1bc7d63 100644 --- a/libafl/src/executors/forkserver.rs +++ b/libafl/src/executors/forkserver.rs @@ -147,6 +147,8 @@ const MIN_INPUT_SIZE_DEFAULT: usize = 1; pub const SHM_FUZZ_ENV_VAR: &str = "__AFL_SHM_FUZZ_ID"; /// Environment variable key for shared memory id for edge map pub const SHM_ENV_VAR: &str = "__AFL_SHM_ID"; +/// Environment variable key for shared memory id for cmplog map +pub const SHM_CMPLOG_ENV_VAR: &str = "__AFL_CMPLOG_SHM_ID"; /// The default signal to use to kill child processes const KILL_SIGNAL_DEFAULT: Signal = Signal::SIGTERM; diff --git a/libafl_targets/src/forkserver.rs b/libafl_targets/src/forkserver.rs index 2bfb1c1f1f..47b81812ca 100644 --- a/libafl_targets/src/forkserver.rs +++ b/libafl_targets/src/forkserver.rs @@ -11,7 +11,7 @@ use libafl::{ Error, executors::forkserver::{ FORKSRV_FD, FS_ERROR_SHM_OPEN, FS_NEW_OPT_AUTODTCT, FS_NEW_OPT_MAPSIZE, - FS_NEW_OPT_SHDMEM_FUZZ, FS_NEW_VERSION_MAX, FS_OPT_ERROR, SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, + FS_NEW_OPT_SHDMEM_FUZZ, FS_NEW_VERSION_MAX, FS_OPT_ERROR, SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, SHM_CMPLOG_ENV_VAR, }, }; use libafl_bolts::os::{ChildHandle, ForkResult}; @@ -22,6 +22,8 @@ use nix::{ }; use crate::coverage::{__afl_map_size, EDGES_MAP_PTR, INPUT_LENGTH_PTR, INPUT_PTR, SHM_FUZZING}; +#[cfg(feature = "cmplog")] +use crate::cmps::CMPLOG_MAP_PTR; #[cfg(any(target_os = "linux", target_vendor = "apple"))] use crate::coverage::{__token_start, __token_stop}; @@ -163,6 +165,46 @@ fn map_input_shared_memory_internal() -> Result<(), Error> { Ok(()) } +/// Guard [`map_cmplog_shared_memory`] is invoked only once +#[cfg(feature = "cmplog")] +static CMPLOG_SHM_MAP_GUARD: OnceLock<()> = OnceLock::new(); + +/// Map the cmplog shared memory region. +/// The [`CMPLOG_MAP_PTR`] will be updated. +/// +/// If anything failed, the forkserver will be notified with +/// [`FS_ERROR_SHM_OPEN`]. +#[cfg(feature = "cmplog")] +pub fn map_cmplog_shared_memory() -> Result<(), Error> { + if CMPLOG_SHM_MAP_GUARD.set(()).is_err() { + return Err(Error::illegal_state("shared memory has been mapped before")); + } + map_cmplog_shared_memory_internal() +} + +#[cfg(feature = "cmplog")] +fn map_cmplog_shared_memory_internal() -> Result<(), Error> { + let Ok(id_str) = std::env::var(SHM_CMPLOG_ENV_VAR) else { + write_error_to_forkserver(FS_ERROR_SHM_OPEN)?; + return Err(Error::illegal_argument( + "Error: variable for cmplog shared memory is not set", + )); + }; + let Ok(shm_id) = id_str.parse() else { + write_error_to_forkserver(FS_ERROR_SHM_OPEN)?; + return Err(Error::illegal_argument("Invalid __AFL_CMPLOG_SHM_ID value")); + }; + let map = unsafe { libc::shmat(shm_id, core::ptr::null(), 0) }; + if map.is_null() || core::ptr::eq(map, libc::MAP_FAILED) { + write_error_to_forkserver(FS_ERROR_SHM_OPEN)?; + return Err(Error::illegal_state("shmat for map")); + } + unsafe { + CMPLOG_MAP_PTR = map.cast(); + } + Ok(()) +} + /// Parent to handle all logics with forkserver children pub trait ForkserverParent { /// Conduct initializing routine before fuzzing loop.