Skip to content

Commit

Permalink
Make MmapShMem::new take a AsRef<Path> instead of a byte array (AFLpl…
Browse files Browse the repository at this point in the history
…usplus#2742)

* Make MmapShMem take a AsRef<Path> instead of a byte array

* Make the test actually test if MmapShMem::persist works

* 0.14.1 (AFLplusplus#2698)

* 0.14.1

* fixer

* don't build nyx

---------

Co-authored-by: Dominik Maier <[email protected]>

* Intel PT minor fixes/improvements (AFLplusplus#2724)

* waitpid_filtered to ignore SIGWINCH

* Fix warnings unused manifest key: *.version

* Add export_raw feature to libafl_intelpt

* derive Debug for IntelPTHook

* Clippy

* Update target program ELF offsets

* Add comment to KVM pt_mode check

* refactor

* Add intel_pt_export_raw feature in libafl

* map_error instead of unwrap

* borrow checker friendly join_split_trace

and copy trace before deocde to prevent decoding failures

* Set ip_filters (also) with builder

* Move trace to file

* Fix Cargo.toml docs

* Ignore blocks with no instruction

most likely they are filtered out

* Fix assertion in snapshot module for pages that are equal to SNAPSHOT_PAGE_SIZE (AFLplusplus#2738)

Co-authored-by: Scott Powell <[email protected]>

* Remove non_basic const_panic features (AFLplusplus#2739)

* Remove non_basic const_panic features

* fmt

* Make FridaInProcessExecutor compatible with TargetBytesConverter, decouple input type from FridaRuntime trait (AFLplusplus#2741)

* decouple input type from FridaRuntime trait

* fmt

* fmt2

* remove HasTargetBytes requirement from FridaInProcessExecutor

* fmt

* restore comment

* fix clippy comment error

* adding entry to MIGRATION.md

* only running persist test on unix

* move cfg dependent imports to function

---------

Co-authored-by: Dongjia "toka" Zhang <[email protected]>
Co-authored-by: Dominik Maier <[email protected]>
Co-authored-by: Marco C. <[email protected]>
Co-authored-by: Scott <[email protected]>
Co-authored-by: Scott Powell <[email protected]>
Co-authored-by: jejuisland87654 <[email protected]>
  • Loading branch information
7 people authored Dec 3, 2024
1 parent 85796f9 commit 2758a1c
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 34 deletions.
3 changes: 3 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
# 0.14.0 -> 0.14.1
- Removed `with_observers` from `Executor` trait.
- `MmapShMemProvider::new_shmem_persistent` has been removed in favour of `MmapShMem::persist`. You probably want to do something like this: `let shmem = MmapShMemProvider::new()?.new_shmem(size)?.persist()?;`

# 0.14.1 -> 0.14.2
- `MmapShMem::new` and `MmapShMemProvider::new_shmem_with_id` now take `AsRef<Path>` instead of a byte array for the filename/id.
104 changes: 70 additions & 34 deletions libafl_bolts/src/shmem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ pub mod unix_shmem {
ops::{Deref, DerefMut},
ptr, slice,
};
use std::{io, process};
use std::{io, path::Path, process};

use libc::{
c_int, c_uchar, close, fcntl, ftruncate, mmap, munmap, shm_open, shm_unlink, shmat,
Expand Down Expand Up @@ -692,26 +692,29 @@ pub mod unix_shmem {
impl MmapShMem {
/// Create a new [`MmapShMem`]
///
/// At most [`MAX_MMAP_FILENAME_LEN`] - 2 values from filename will be used. Do not include any characters that are illegal as filenames
/// At most [`MAX_MMAP_FILENAME_LEN`] - 2 bytes from filename will be used.
///
/// This will *NOT* automatically delete the shmem files, meaning that it's user's responsibility to delete them after fuzzing
pub fn new(map_size: usize, filename: &[u8]) -> Result<Self, Error> {
pub fn new(map_size: usize, filename: impl AsRef<Path>) -> Result<Self, Error> {
let filename_bytes = filename.as_ref().as_os_str().as_encoded_bytes();

let mut filename_path: [u8; 20] = [0_u8; MAX_MMAP_FILENAME_LEN];
// Keep room for the leading slash and trailing NULL.
let max_copy = usize::min(filename_bytes.len(), MAX_MMAP_FILENAME_LEN - 2);
filename_path[0] = b'/';
filename_path[1..=max_copy].copy_from_slice(&filename_bytes[..max_copy]);

log::info!(
"{} Creating shmem {} {:?}",
map_size,
process::id(),
filename_path
);

// # Safety
// No user-provided potentially unsafe parameters.
// FFI Calls.
unsafe {
let mut filename_path: [u8; 20] = [0_u8; MAX_MMAP_FILENAME_LEN];
// Keep room for the leading slash and trailing NULL.
let max_copy = usize::min(filename.len(), MAX_MMAP_FILENAME_LEN - 2);
filename_path[0] = b'/';
filename_path[1..=max_copy].copy_from_slice(&filename[..max_copy]);

log::info!(
"{} Creating shmem {} {:#?}",
map_size,
process::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 _,
Expand Down Expand Up @@ -942,12 +945,12 @@ pub mod unix_shmem {
impl MmapShMemProvider {
/// Create a [`MmapShMem`] with the specified size and id.
///
/// At most [`MAX_MMAP_FILENAME_LEN`] - 2 values from filename will be used. Do not include any characters that are illegal as filenames.
/// At most [`MAX_MMAP_FILENAME_LEN`] - 2 bytes from id will be used.
#[cfg(any(unix, doc))]
pub fn new_shmem_with_id(
&mut self,
map_size: usize,
id: &[u8],
id: impl AsRef<Path>,
) -> Result<MmapShMem, Error> {
MmapShMem::new(map_size, id)
}
Expand All @@ -974,10 +977,10 @@ pub mod unix_shmem {
fn new_shmem(&mut self, map_size: usize) -> Result<Self::ShMem, Error> {
let mut rand = StdRand::with_seed(crate::rands::random_seed());
let id = rand.next() as u32;
let mut full_file_name = format!("/libafl_{}_{}", process::id(), id);
let mut full_file_name = format!("libafl_{}_{}", process::id(), id);
// leave one byte space for the null byte.
full_file_name.truncate(MAX_MMAP_FILENAME_LEN - 1);
MmapShMem::new(map_size, full_file_name.as_bytes())
MmapShMem::new(map_size, full_file_name)
}

fn shmem_from_id_and_size(
Expand Down Expand Up @@ -1844,27 +1847,60 @@ mod tests {
}

#[test]
#[cfg(all(unix, not(miri)))]
#[cfg(unix)]
#[cfg_attr(miri, ignore)]
fn test_persist_shmem() -> Result<(), Error> {
use std::thread;
use core::ffi::CStr;
use std::{
env,
process::{Command, Stdio},
string::ToString,
};

use crate::shmem::{MmapShMemProvider, ShMem as _};
use crate::shmem::{MmapShMemProvider, ShMem as _, ShMemId};

let mut provider = MmapShMemProvider::new()?;
let mut shmem = provider.new_shmem(1)?.persist()?;
shmem.fill(0);
// relies on the fact that the ID in a ShMemDescription is always a string for MmapShMem
match env::var("SHMEM_SIZE") {
Ok(size) => {
let mut provider = MmapShMemProvider::new()?;
let id = ShMemId::from_string(&env::var("SHMEM_ID").unwrap());
let size = size.parse().unwrap();
let mut shmem = provider.shmem_from_id_and_size(id, size)?;
shmem[0] = 1;
}
Err(env::VarError::NotPresent) => {
let mut provider = MmapShMemProvider::new()?;
let mut shmem = provider.new_shmem(1)?.persist()?;
shmem.fill(0);
let description = shmem.description();

// call the test binary again
// with certain env variables set to prevent infinite loops
// and with an added arg to only run this test
//
// a command is necessary to create the required distance between the two processes
// with threads/fork it works without the additional steps to persist the ShMem regardless
let status = Command::new(env::current_exe().unwrap())
.env(
"SHMEM_ID",
CStr::from_bytes_until_nul(description.id.as_array())
.unwrap()
.to_str()
.unwrap(),
)
.env("SHMEM_SIZE", description.size.to_string())
.arg("shmem::tests::test_persist_shmem")
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.unwrap();

let description = shmem.description();
assert!(status.success());
assert_eq!(shmem[0], 1);
}
Err(e) => panic!("{e}"),
}

let handle = thread::spawn(move || -> Result<(), Error> {
let mut provider = MmapShMemProvider::new()?;
let mut shmem = provider.shmem_from_description(description)?;
shmem.as_slice_mut()[0] = 1;
Ok(())
});
handle.join().unwrap()?;
assert_eq!(1, shmem.as_slice()[0]);
Ok(())
}
}

0 comments on commit 2758a1c

Please sign in to comment.