Use filename for MmapShMemProvider (#2303)

* fixer

* comment

* a

* bb

* apple
This commit is contained in:
Dongjia "toka" Zhang 2024-06-11 20:15:11 +02:00 committed by GitHub
parent 03d8d2eb08
commit 0ed295842b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 98 additions and 64 deletions

View File

@ -20,7 +20,7 @@ which = "4.4"
[dependencies] [dependencies]
libafl = { path = "../../libafl/", features = ["std", "derive", "rand_trait", "fork", "prelude", "gzip", "regex", "scalability_introspection"] } 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"] } libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] }
# TODO Include it only when building cc # TODO Include it only when building cc
libafl_cc = { path = "../../libafl_cc/" } libafl_cc = { path = "../../libafl_cc/" }

View File

@ -19,8 +19,9 @@ cc = { version = "1.0", features = ["parallel"] }
which = "4.4" which = "4.4"
[dependencies] [dependencies]
env_logger = "0.10"
libafl = { path = "../../libafl/" } 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"] } libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] }
# TODO Include it only when building cc # TODO Include it only when building cc
libafl_cc = { path = "../../libafl_cc/" } libafl_cc = { path = "../../libafl_cc/" }

View File

@ -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 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] [tasks.cc]
linux_alias = "cc_unix" linux_alias = "cc_unix"
mac_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}" 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" 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 # Harness
@ -73,7 +63,7 @@ windows_alias = "unsupported"
[tasks.fuzzer_unix] [tasks.fuzzer_unix]
command = "${CARGO_TARGET_DIR}/${PROFILE_DIR}/libafl_cxx" 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"] 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 # Run the fuzzer
[tasks.run] [tasks.run]

View File

@ -32,7 +32,7 @@ use libafl::{
use libafl_bolts::{ use libafl_bolts::{
core_affinity::Cores, core_affinity::Cores,
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{MmapShMemProvider, ShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice, AsSlice,
}; };
@ -142,7 +142,7 @@ pub extern "C" fn libafl_main() {
// Needed only on no_std // Needed only on no_std
// unsafe { RegistryBuilder::register::<Tokens>(); } // unsafe { RegistryBuilder::register::<Tokens>(); }
let opt = Opt::parse(); let opt = Opt::parse();
env_logger::init();
let broker_port = opt.broker_port; let broker_port = opt.broker_port;
let cores = opt.cores; let cores = opt.cores;
@ -152,7 +152,7 @@ pub extern "C" fn libafl_main() {
opt.reload_corpus 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( let monitor = OnDiskTOMLMonitor::new(
"./fuzzer_stats.toml", "./fuzzer_stats.toml",

View File

@ -644,13 +644,14 @@ pub mod unix_shmem {
#[cfg(all(unix, feature = "std", not(target_os = "android")))] #[cfg(all(unix, feature = "std", not(target_os = "android")))]
mod default { mod default {
#[cfg(target_vendor = "apple")]
use alloc::string::ToString; use alloc::string::ToString;
use core::{ use core::{
ffi::CStr, ffi::CStr,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
ptr, slice, ptr, slice,
}; };
use std::{io::Write, process}; use std::process;
use libc::{ use libc::{
c_int, c_uchar, close, ftruncate, mmap, munmap, shm_open, shm_unlink, shmat, shmctl, c_int, c_uchar, close, ftruncate, mmap, munmap, shm_open, shm_unlink, shmat, shmctl,
@ -663,13 +664,7 @@ pub mod unix_shmem {
Error, Error,
}; };
// This is macOS's limit const MAX_MMAP_FILENAME_LEN: usize = 20;
// 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;
/// Mmap-based The sharedmap impl for unix using [`shm_open`] and [`mmap`]. /// 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 /// Default on `MacOS` and `iOS`, where we need a central point to unmap
@ -691,22 +686,27 @@ pub mod unix_shmem {
impl MmapShMem { impl MmapShMem {
/// Create a new [`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<Self, Error> { pub fn new(map_size: usize, rand_id: u32) -> Result<Self, Error> {
unsafe { unsafe {
let full_file_name = format!("/libafl_{}_{}", process::id(), rand_id);
let mut filename_path = [0_u8; MAX_MMAP_FILENAME_LEN]; let mut filename_path = [0_u8; MAX_MMAP_FILENAME_LEN];
write!( filename_path
&mut filename_path[..MAX_MMAP_FILENAME_LEN - 1], .copy_from_slice(&full_file_name.as_bytes()[..MAX_MMAP_FILENAME_LEN]);
"/libafl_{}_{}", filename_path[MAX_MMAP_FILENAME_LEN - 1] = 0; // Null terminate!
log::info!(
"{} Creating shmem {} {:#?}",
map_size,
process::id(), process::id(),
rand_id filename_path
)?; );
/* create the shared memory segment as if it was a file */ /* create the shared memory segment as if it was a file */
let shm_fd = shm_open( let shm_fd = shm_open(
filename_path.as_ptr() as *const _, filename_path.as_ptr() as *const _,
libc::O_CREAT | libc::O_RDWR | libc::O_EXCL, libc::O_CREAT | libc::O_RDWR | libc::O_EXCL,
0o600, 0o600,
); );
if shm_fd == -1 { if shm_fd == -1 {
return Err(Error::last_os_error(format!( return Err(Error::last_os_error(format!(
"Failed to shm_open map with id {filename_path:?}", "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 { Ok(Self {
filename_path: Some(filename_path), filename_path: Some(filename_path),
map: map as *mut u8, map: map as *mut u8,
map_size, map_size,
shm_fd, 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<Self, Error> { fn shmem_from_id_and_size(id: ShMemId, map_size: usize) -> Result<Self, Error> {
unsafe { unsafe {
let shm_fd: i32 = id.to_string().parse().unwrap();
/* map the shared memory segment to the address space of the process */ /* map the shared memory segment to the address space of the process */
let map = mmap( #[cfg(target_vendor = "apple")]
ptr::null_mut(), let (map, shm_fd) = {
map_size, let shm_fd: i32 = id.to_string().parse().unwrap();
libc::PROT_READ | libc::PROT_WRITE, let map = mmap(
libc::MAP_SHARED, ptr::null_mut(),
shm_fd, map_size,
0, libc::PROT_READ | libc::PROT_WRITE,
); libc::MAP_SHARED,
if map == libc::MAP_FAILED || map.is_null() { shm_fd,
close(shm_fd); 0,
return Err(Error::last_os_error(format!( );
"mmap() failed for map with fd {shm_fd:?}" (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 { Ok(Self {
filename_path: None, filename_path: None,
map: map as *mut u8, map: map as *mut u8,
map_size, map_size,
shm_fd, 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. /// A [`ShMemProvider`] which uses [`shm_open`] and [`mmap`] to provide shared memory mappings.
#[cfg(unix)] #[cfg(unix)]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MmapShMemProvider { pub struct MmapShMemProvider {}
rand: StdRand,
}
unsafe impl Send for MmapShMemProvider {} unsafe impl Send for MmapShMemProvider {}
@ -807,12 +847,11 @@ pub mod unix_shmem {
type ShMem = MmapShMem; type ShMem = MmapShMem;
fn new() -> Result<Self, Error> { fn new() -> Result<Self, Error> {
Ok(Self { Ok(Self {})
rand: StdRand::new(),
})
} }
fn new_shmem(&mut self, map_size: usize) -> Result<Self::ShMem, Error> { fn new_shmem(&mut self, map_size: usize) -> Result<Self::ShMem, Error> {
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) 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. // None in case we didn't [`shm_open`] this ourselves, but someone sent us the FD.
if let Some(filename_path) = self.filename_path { // log::info!("Dropping {:#?}", self.filename_path);
shm_unlink(filename_path.as_ptr() as *const _); // 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.
} }
} }
} }

View File

@ -57,10 +57,11 @@ fn main() {
); );
// std::fs::write("compiler_output.txt", output_str.clone()).expect("Unable to write file"); // std::fs::write("compiler_output.txt", output_str.clone()).expect("Unable to write file");
assert!(output.status.success(), assert!(
"Failed to link test_harness.dll\n {:?}", output.status.success(),
output_str.as_str() "Failed to link test_harness.dll\n {:?}",
); output_str.as_str()
);
} else { } else {
let compiler = cc::Build::new() let compiler = cc::Build::new()
.cpp(true) .cpp(true)

View File

@ -17,7 +17,6 @@ use libafl::executors::{hooks::ExecutorHook, HasObservers};
))] ))]
use crate::coverage::EDGES_MAP; use crate::coverage::EDGES_MAP;
use crate::coverage::MAX_EDGES_FOUND; use crate::coverage::MAX_EDGES_FOUND;
#[cfg(feature = "sancov_ngram4")] #[cfg(feature = "sancov_ngram4")]
#[allow(unused)] #[allow(unused)]
use crate::EDGES_MAP_SIZE_IN_USE; use crate::EDGES_MAP_SIZE_IN_USE;