From 0ed295842b86560e1903b19a82af355591f86933 Mon Sep 17 00:00:00 2001 From: "Dongjia \"toka\" Zhang" Date: Tue, 11 Jun 2024 20:15:11 +0200 Subject: [PATCH] Use filename for MmapShMemProvider (#2303) * fixer * comment * a * bb * apple --- .../libfuzzer_libpng_centralized/Cargo.toml | 2 +- fuzzers/libfuzzer_libpng_norestart/Cargo.toml | 3 +- .../libfuzzer_libpng_norestart/Makefile.toml | 14 +- fuzzers/libfuzzer_libpng_norestart/src/lib.rs | 6 +- libafl_bolts/src/shmem.rs | 127 ++++++++++++------ libafl_frida/build.rs | 9 +- libafl_targets/src/sancov_pcguard.rs | 1 - 7 files changed, 98 insertions(+), 64 deletions(-) diff --git a/fuzzers/libfuzzer_libpng_centralized/Cargo.toml b/fuzzers/libfuzzer_libpng_centralized/Cargo.toml index 74766d032a..02ff9fcabe 100644 --- a/fuzzers/libfuzzer_libpng_centralized/Cargo.toml +++ b/fuzzers/libfuzzer_libpng_centralized/Cargo.toml @@ -20,7 +20,7 @@ which = "4.4" [dependencies] libafl = { path = "../../libafl/", features = ["std", "derive", "rand_trait", "fork", "prelude", "gzip", "regex", "scalability_introspection"] } -libafl_bolts = { path = "../../libafl_bolts/" } +libafl_bolts = { path = "../../libafl_bolts/", features = ["errors_backtrace"] } libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] } # TODO Include it only when building cc libafl_cc = { path = "../../libafl_cc/" } diff --git a/fuzzers/libfuzzer_libpng_norestart/Cargo.toml b/fuzzers/libfuzzer_libpng_norestart/Cargo.toml index ec926fca9e..0383fc89d9 100644 --- a/fuzzers/libfuzzer_libpng_norestart/Cargo.toml +++ b/fuzzers/libfuzzer_libpng_norestart/Cargo.toml @@ -19,8 +19,9 @@ cc = { version = "1.0", features = ["parallel"] } which = "4.4" [dependencies] +env_logger = "0.10" libafl = { path = "../../libafl/" } -libafl_bolts = { path = "../../libafl_bolts/" } +libafl_bolts = { path = "../../libafl_bolts/", features = ["errors_backtrace"] } libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] } # TODO Include it only when building cc libafl_cc = { path = "../../libafl_cc/" } diff --git a/fuzzers/libfuzzer_libpng_norestart/Makefile.toml b/fuzzers/libfuzzer_libpng_norestart/Makefile.toml index a696ff7f42..e63e7bc674 100644 --- a/fuzzers/libfuzzer_libpng_norestart/Makefile.toml +++ b/fuzzers/libfuzzer_libpng_norestart/Makefile.toml @@ -29,16 +29,6 @@ wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz tar -xvf v1.6.37.tar.gz ''' -# Compilers -[tasks.cxx] -linux_alias = "cxx_unix" -mac_alias = "cxx_unix" -windows_alias = "unsupported" - -[tasks.cxx_unix] -command = "cargo" -args = ["build" , "--profile", "${PROFILE}"] - [tasks.cc] linux_alias = "cc_unix" mac_alias = "cc_unix" @@ -61,7 +51,7 @@ cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardw cd "${PROJECT_DIR}" make -C libpng-1.6.37 CC="${CARGO_TARGET_DIR}/${PROFILE_DIR}/libafl_cc" CXX="${CARGO_TARGET_DIR}/${PROFILE_DIR}/libafl_cxx" ''' -dependencies = [ "libpng", "cxx", "cc" ] +dependencies = [ "libpng", "cc" ] # Harness @@ -73,7 +63,7 @@ windows_alias = "unsupported" [tasks.fuzzer_unix] command = "${CARGO_TARGET_DIR}/${PROFILE_DIR}/libafl_cxx" args = ["${PROJECT_DIR}/harness.cc", "${PROJECT_DIR}/libpng-1.6.37/.libs/libpng16.a", "-I", "${PROJECT_DIR}/libpng-1.6.37/", "-o", "${FUZZER_NAME}", "-lm", "-lz"] -dependencies = [ "lib", "cxx", "cc" ] +dependencies = [ "lib", "cc" ] # Run the fuzzer [tasks.run] diff --git a/fuzzers/libfuzzer_libpng_norestart/src/lib.rs b/fuzzers/libfuzzer_libpng_norestart/src/lib.rs index f21f4baa64..a792467aaf 100644 --- a/fuzzers/libfuzzer_libpng_norestart/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_norestart/src/lib.rs @@ -32,7 +32,7 @@ use libafl::{ use libafl_bolts::{ core_affinity::Cores, rands::StdRand, - shmem::{ShMemProvider, StdShMemProvider}, + shmem::{MmapShMemProvider, ShMemProvider}, tuples::{tuple_list, Merge}, AsSlice, }; @@ -142,7 +142,7 @@ pub extern "C" fn libafl_main() { // Needed only on no_std // unsafe { RegistryBuilder::register::(); } let opt = Opt::parse(); - + env_logger::init(); let broker_port = opt.broker_port; let cores = opt.cores; @@ -152,7 +152,7 @@ pub extern "C" fn libafl_main() { opt.reload_corpus ); - let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory"); + let shmem_provider = MmapShMemProvider::new().expect("Failed to init shared memory"); let monitor = OnDiskTOMLMonitor::new( "./fuzzer_stats.toml", diff --git a/libafl_bolts/src/shmem.rs b/libafl_bolts/src/shmem.rs index 3be93fdb8c..fb06682134 100644 --- a/libafl_bolts/src/shmem.rs +++ b/libafl_bolts/src/shmem.rs @@ -644,13 +644,14 @@ pub mod unix_shmem { #[cfg(all(unix, feature = "std", not(target_os = "android")))] mod default { + #[cfg(target_vendor = "apple")] use alloc::string::ToString; use core::{ ffi::CStr, ops::{Deref, DerefMut}, ptr, slice, }; - use std::{io::Write, process}; + use std::process; use libc::{ c_int, c_uchar, close, ftruncate, mmap, munmap, shm_open, shm_unlink, shmat, shmctl, @@ -663,13 +664,7 @@ pub mod unix_shmem { Error, }; - // This is macOS's limit - // https://stackoverflow.com/questions/38049068/osx-shm-open-returns-enametoolong - #[cfg(target_vendor = "apple")] - const MAX_MMAP_FILENAME_LEN: usize = 31; - - #[cfg(not(target_vendor = "apple"))] - const MAX_MMAP_FILENAME_LEN: usize = 256; + const MAX_MMAP_FILENAME_LEN: usize = 20; /// Mmap-based The sharedmap impl for unix using [`shm_open`] and [`mmap`]. /// Default on `MacOS` and `iOS`, where we need a central point to unmap @@ -691,22 +686,27 @@ pub mod unix_shmem { impl MmapShMem { /// Create a new [`MmapShMem`] + /// This will *NOT* automatically delete the shmem files, meaning that it's user's responsibility to delete all `/dev/shm/libafl_*` after fuzzing pub fn new(map_size: usize, rand_id: u32) -> Result { unsafe { + let full_file_name = format!("/libafl_{}_{}", process::id(), rand_id); let mut filename_path = [0_u8; MAX_MMAP_FILENAME_LEN]; - write!( - &mut filename_path[..MAX_MMAP_FILENAME_LEN - 1], - "/libafl_{}_{}", + filename_path + .copy_from_slice(&full_file_name.as_bytes()[..MAX_MMAP_FILENAME_LEN]); + filename_path[MAX_MMAP_FILENAME_LEN - 1] = 0; // Null terminate! + log::info!( + "{} Creating shmem {} {:#?}", + map_size, process::id(), - rand_id - )?; - + filename_path + ); /* create the shared memory segment as if it was a file */ let shm_fd = shm_open( filename_path.as_ptr() as *const _, libc::O_CREAT | libc::O_RDWR | libc::O_EXCL, 0o600, ); + if shm_fd == -1 { return Err(Error::last_os_error(format!( "Failed to shm_open map with id {filename_path:?}", @@ -738,42 +738,84 @@ pub mod unix_shmem { ))); } + // Apple uses it for served shmem provider, which uses fd + // Others will just use filename + + #[cfg(target_vendor = "apple")] + let id = ShMemId::from_string(&format!("{shm_fd}")); + #[cfg(not(target_vendor = "apple"))] + let id = ShMemId::from_string(core::str::from_utf8(&filename_path)?); + Ok(Self { filename_path: Some(filename_path), map: map as *mut u8, map_size, shm_fd, - id: ShMemId::from_string(&format!("{shm_fd}")), + id, }) } } + #[allow(clippy::unnecessary_wraps)] fn shmem_from_id_and_size(id: ShMemId, map_size: usize) -> Result { unsafe { - let shm_fd: i32 = id.to_string().parse().unwrap(); - /* map the shared memory segment to the address space of the process */ - let map = mmap( - ptr::null_mut(), - map_size, - libc::PROT_READ | libc::PROT_WRITE, - libc::MAP_SHARED, - shm_fd, - 0, - ); - if map == libc::MAP_FAILED || map.is_null() { - close(shm_fd); - return Err(Error::last_os_error(format!( - "mmap() failed for map with fd {shm_fd:?}" - ))); - } + #[cfg(target_vendor = "apple")] + let (map, shm_fd) = { + let shm_fd: i32 = id.to_string().parse().unwrap(); + let map = mmap( + ptr::null_mut(), + map_size, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_SHARED, + shm_fd, + 0, + ); + (map, shm_fd) + }; + + #[cfg(not(target_vendor = "apple"))] + let (map, shm_fd) = { + let mut filename_path = [0_u8; MAX_MMAP_FILENAME_LEN]; + filename_path.copy_from_slice(&id.id); + + /* attach to the shared memory segment as if it was a file */ + let shm_fd = + shm_open(filename_path.as_ptr() as *const _, libc::O_RDWR, 0o600); + if shm_fd == -1 { + log::info!( + "Trying to attach to {:#?} but failed {}", + filename_path, + process::id() + ); + return Err(Error::last_os_error(format!( + "Failed to shm_open map with id {filename_path:?}", + ))); + } + /* map the shared memory segment to the address space of the process */ + let map = mmap( + ptr::null_mut(), + map_size, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_SHARED, + shm_fd, + 0, + ); + if map == libc::MAP_FAILED || map.is_null() { + close(shm_fd); + return Err(Error::last_os_error(format!( + "mmap() failed for map with fd {shm_fd:?}" + ))); + } + (map, shm_fd) + }; Ok(Self { filename_path: None, map: map as *mut u8, map_size, shm_fd, - id: ShMemId::from_string(&format!("{shm_fd}")), + id, }) } } @@ -788,9 +830,7 @@ pub mod unix_shmem { /// A [`ShMemProvider`] which uses [`shm_open`] and [`mmap`] to provide shared memory mappings. #[cfg(unix)] #[derive(Clone, Debug)] - pub struct MmapShMemProvider { - rand: StdRand, - } + pub struct MmapShMemProvider {} unsafe impl Send for MmapShMemProvider {} @@ -807,12 +847,11 @@ pub mod unix_shmem { type ShMem = MmapShMem; fn new() -> Result { - Ok(Self { - rand: StdRand::new(), - }) + Ok(Self {}) } fn new_shmem(&mut self, map_size: usize) -> Result { - let id = self.rand.next() as u32; + let mut rand = StdRand::with_seed(crate::rands::random_seed()); + let id = rand.next() as u32; MmapShMem::new(map_size, id) } @@ -872,9 +911,13 @@ pub mod unix_shmem { ); // None in case we didn't [`shm_open`] this ourselves, but someone sent us the FD. - if let Some(filename_path) = self.filename_path { - shm_unlink(filename_path.as_ptr() as *const _); - } + // log::info!("Dropping {:#?}", self.filename_path); + // if let Some(filename_path) = self.filename_path { + // shm_unlink(filename_path.as_ptr() as *const _); + // } + // We cannot shm_unlink here! + // unlike unix common shmem we don't have refcounter. + // so there's no guarantee that there's no other process still using it. } } } diff --git a/libafl_frida/build.rs b/libafl_frida/build.rs index 72487f079f..76669ec895 100644 --- a/libafl_frida/build.rs +++ b/libafl_frida/build.rs @@ -57,10 +57,11 @@ fn main() { ); // std::fs::write("compiler_output.txt", output_str.clone()).expect("Unable to write file"); - assert!(output.status.success(), - "Failed to link test_harness.dll\n {:?}", - output_str.as_str() - ); + assert!( + output.status.success(), + "Failed to link test_harness.dll\n {:?}", + output_str.as_str() + ); } else { let compiler = cc::Build::new() .cpp(true) diff --git a/libafl_targets/src/sancov_pcguard.rs b/libafl_targets/src/sancov_pcguard.rs index 9ebcb3a6c5..0bd584d3f6 100644 --- a/libafl_targets/src/sancov_pcguard.rs +++ b/libafl_targets/src/sancov_pcguard.rs @@ -17,7 +17,6 @@ use libafl::executors::{hooks::ExecutorHook, HasObservers}; ))] use crate::coverage::EDGES_MAP; use crate::coverage::MAX_EDGES_FOUND; - #[cfg(feature = "sancov_ngram4")] #[allow(unused)] use crate::EDGES_MAP_SIZE_IN_USE;