ShMem Server for MacOS (#238)

* generalized ashmem server

* fixed macos testcases

* added StdShMemService

* no_st

* fmt

* added testcase, fixed some bugs (not all)

* solidified unix shmem

* initial impl for MmapShMem

* Added shmem service start to more testcases

* clippy

* fixed tetcases

* added frida_libpng makefile for easy use

* trying to fix build on ubuntu

* fixed ubuntu build for libpng

* no_std

* fixed testcase
This commit is contained in:
Dominik Maier 2021-08-05 17:08:01 +02:00 committed by GitHub
parent 704830a501
commit 16c3a07be7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 615 additions and 139 deletions

View File

@ -97,7 +97,7 @@ pub fn main() {
#[cfg(any(windows, unix))]
unsafe {
printf(
[b'%' as c_char, b's' as c_char, b'\n' as c_char, 0 as c_char].as_ptr(),
b"%s\n\0".as_ptr() as *const c_char,
CString::new(s).unwrap().as_ptr() as *const c_char,
);
}

View File

@ -3,7 +3,7 @@ use libafl::{
bolts::{
current_nanos,
rands::StdRand,
shmem::{ShMem, ShMemProvider, StdShMemProvider},
shmem::{ShMem, ShMemProvider, StdShMemProvider, StdShMemService},
tuples::tuple_list,
},
corpus::{
@ -29,6 +29,9 @@ pub fn main() {
let corpus_dirs = vec![PathBuf::from("./corpus")];
const MAP_SIZE: usize = 65536;
let _service = StdShMemService::start().unwrap();
//Coverage map shared between observer and executor
let mut shmem = StdShMemProvider::new().unwrap().new_map(MAP_SIZE).unwrap();
//let the forkserver know the shmid

View File

@ -1 +1,3 @@
libpng-*
corpus_discovered
libafl_frida

View File

@ -0,0 +1,39 @@
FUZZER_NAME="libafl_frida"
PROJECT_DIR=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
PHONY: all
all: libafl_frida libpng-harness.so
libpng-1.6.37:
wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
tar -xvf libpng-1.6.37.tar.xz
target/release/frida_libpng: src/*
# Build the frida libpng libfuzzer fuzzer
cargo build --release
libpng-1.6.37/.libs/libpng16.a: libpng-1.6.37
cd libpng-1.6.37 && ./configure --enable-hardware-optimizations=yes --with-pic=yes
$(MAKE) -C libpng-1.6.37
libpng-harness.so: libpng-1.6.37/.libs/libpng16.a
$(CXX) -O3 -c -fPIC harness.cc -o harness.o
$(CXX) -O3 harness.o libpng-1.6.37/.libs/libpng16.a -shared -lz -o libpng-harness.so
libafl_frida: target/release/frida_libpng
cp target/release/frida_libpng libafl_frida
clean:
$(MAKE) -C libpng-1.6.37 clean
rm $(FUZZER_NAME)
run: all
./$(FUZZER_NAME) ./libpng-harness.so LLVMFuzzerTestOneInput ./libpng-harness.so --cores=0
short_test: all
# We allow exit code 124 too, which is sigterm
(timeout 3s ./libafl_frida ./libpng-harness.so LLVMFuzzerTestOneInput ./libpng-harness.so --cores=0,1 || [ $$? -eq 124 ])
test: all
timeout 60s ./$(FUZZER_NAME) ./libpng-harness.so LLVMFuzzerTestOneInput ./libpng-harness.so --cores=0,1

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

View File

@ -3,8 +3,8 @@
use clap::{App, Arg};
#[cfg(target_os = "android")]
use libafl::bolts::os::ashmem_server::AshmemService;
#[cfg(all(cfg = "std", unix))]
use libafl::bolts::os::unix_shmem_server::ShMemService;
use libafl::{
bolts::{
@ -12,7 +12,7 @@ use libafl::{
launcher::Launcher,
os::parse_core_bind_arg,
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
shmem::{ShMemProvider, StdShMemProvider, StdShMemService},
tuples::{tuple_list, Merge},
},
corpus::{
@ -233,7 +233,7 @@ pub fn main() {
.map(|addrstr| addrstr.parse().unwrap());
unsafe {
fuzz(
match fuzz(
matches.value_of("harness").unwrap(),
matches.value_of("symbol").unwrap(),
&matches
@ -252,8 +252,10 @@ pub fn main() {
.value_of("configuration")
.unwrap_or("default launcher")
.to_string(),
)
.expect("An error occurred while fuzzing");
) {
Ok(()) | Err(Error::ShuttingDown) => println!("Finished fuzzing. Good bye."),
Err(e) => panic!("Error during fuzzing: {:?}", e),
}
}
}
@ -292,8 +294,7 @@ unsafe fn fuzz(
// 'While the stats are state, they are usually used in the broker - which is likely never restarted
let stats = MultiStats::new(|s| println!("{}", s));
#[cfg(target_os = "android")]
AshmemService::start().expect("Failed to start Ashmem service");
let _service = StdShMemService::start().expect("Failed to start ShMem service");
let shmem_provider = StdShMemProvider::new()?;
let mut run_client = |state: Option<StdState<_, _, _, _, _>>, mut mgr| {
@ -317,7 +318,7 @@ unsafe fn fuzz(
&gum,
&frida_options,
module_name,
&modules_to_instrument,
modules_to_instrument,
);
// Create an observation channel using the coverage map
@ -411,7 +412,7 @@ unsafe fn fuzz(
// In case the corpus is empty (on first run), reset
if state.corpus().count() < 1 {
state
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &corpus_dirs)
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, corpus_dirs)
.unwrap_or_else(|_| panic!("Failed to load initial corpus at {:?}", &corpus_dirs));
println!("We imported {} inputs from disk.", state.corpus().count());
}

View File

@ -19,7 +19,7 @@ use libafl::{
current_nanos, current_time,
os::dup2,
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
shmem::{ShMemProvider, StdShMemProvider, StdShMemService},
tuples::{tuple_list, Merge},
},
corpus::{Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, QueueCorpusScheduler},
@ -181,8 +181,7 @@ fn fuzz(
// We need a shared map to store our state before a crash.
// This way, we are able to continue fuzzing afterwards.
#[cfg(target_os = "android")]
AshmemService::start().expect("Failed to start Ashmem service");
let _service = StdShMemService::start().expect("Failed to start ShMem service");
let mut shmem_provider = StdShMemProvider::new()?;
let (state, mut mgr) = match SimpleRestartingEventManager::launch(stats, &mut shmem_provider) {

View File

@ -19,7 +19,7 @@ use libafl::{
current_nanos, current_time,
os::dup2,
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
shmem::{ShMemProvider, StdShMemProvider, StdShMemService},
tuples::{tuple_list, Merge},
},
corpus::{Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, QueueCorpusScheduler},

View File

@ -11,7 +11,7 @@ use libafl::{
launcher::Launcher,
os::parse_core_bind_arg,
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
shmem::{ShMemProvider, StdShMemProvider, StdShMemService},
tuples::{tuple_list, Merge},
},
corpus::{
@ -78,8 +78,7 @@ pub fn libafl_main() {
println!("Workdir: {:?}", workdir.to_string_lossy().to_string());
#[cfg(target_os = "android")]
AshmemService::start().expect("Failed to start Ashmem service");
let _service = StdShMemService::start().expect("Failed to start ShMem service");
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
let stats = MultiStats::new(|s| println!("{}", s));

View File

@ -13,7 +13,7 @@ use libafl::{
launcher::Launcher,
os::parse_core_bind_arg,
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
shmem::{ShMemProvider, StdShMemProvider, StdShMemService},
tuples::{tuple_list, Merge},
},
corpus::{
@ -54,8 +54,7 @@ pub fn libafl_main() {
env::current_dir().unwrap().to_string_lossy().to_string()
);
#[cfg(target_os = "android")]
AshmemService::start().expect("Failed to start Ashmem service");
let _service = StdShMemService::start().expect("Failed to start ShMem service");
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
let stats = MultiStats::new(|s| println!("{}", s));

View File

@ -21,6 +21,7 @@ fxhash = "0.2.1" # yet another hash
xxhash-rust = { version = "0.8.2", features = ["xxh3"] } # xxh3 hashing for rust
serde_json = "1.0.60"
num_cpus = "1.0" # cpu count, for llmp example
serial_test = "0.5"
[[bench]]
name = "rand_speeds"

View File

@ -117,6 +117,8 @@ fn main() {
#[cfg(unix)]
fn main() {
use libafl::bolts::shmem::StdShMemService;
/* The main node has a broker, and a few worker threads */
let mode = std::env::args()
@ -137,6 +139,9 @@ fn main() {
match mode.as_str() {
"broker" => {
// The shmem service is needed on some platforms like Android and MacOS
let _service = StdShMemService::start().unwrap();
let mut broker = llmp::LlmpBroker::new(StdShMemProvider::new().unwrap()).unwrap();
broker.launch_tcp_listener_on(port).unwrap();
broker.loop_forever(&mut broker_message_hook, Some(Duration::from_millis(5)))

View File

@ -2650,6 +2650,8 @@ mod tests {
use std::{thread::sleep, time::Duration};
use serial_test::serial;
use super::{
LlmpClient,
LlmpConnection::{self, IsBroker, IsClient},
@ -2657,10 +2659,14 @@ mod tests {
Tag,
};
use crate::bolts::shmem::{ShMemProvider, StdShMemProvider};
use crate::bolts::shmem::{ShMemProvider, StdShMemProvider, StdShMemService};
#[test]
#[serial]
pub fn llmp_connection() {
#[allow(unused_variables)]
let service = StdShMemService::start().unwrap();
let shmem_provider = StdShMemProvider::new().unwrap();
let mut broker = match LlmpConnection::on_port(shmem_provider.clone(), 1337).unwrap() {
IsClient { client: _ } => panic!("Could not bind to port as broker"),

View File

@ -7,7 +7,7 @@ use crate::Error;
use std::{env, process::Command};
#[cfg(all(unix, feature = "std"))]
pub mod ashmem_server;
pub mod unix_shmem_server;
#[cfg(unix)]
pub mod unix_signals;

View File

@ -1,14 +1,12 @@
/*!
On Android, we can only share maps between processes by serializing fds over sockets.
Hence, the `ashmem_server` keeps track of existing maps, creates new maps for clients,
On `Android`, we can only share maps between processes by serializing fds over sockets.
On `MacOS`, we cannot rely on reference counting for Maps.
Hence, the [`unix_shmem_server`] keeps track of existing maps, creates new maps for clients,
and forwards them over unix domain sockets.
*/
use crate::{
bolts::shmem::{
unix_shmem::ashmem::{AshmemShMem, AshmemShMemProvider},
ShMem, ShMemDescription, ShMemId, ShMemProvider,
},
bolts::shmem::{ShMem, ShMemDescription, ShMemId, ShMemProvider},
Error,
};
use core::mem::ManuallyDrop;
@ -16,9 +14,12 @@ use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use std::{
cell::RefCell,
fs,
io::{Read, Write},
marker::PhantomData,
rc::{Rc, Weak},
sync::{Arc, Condvar, Mutex},
thread::JoinHandle,
};
#[cfg(all(feature = "std", unix))]
@ -36,25 +37,36 @@ use std::{
#[cfg(all(unix, feature = "std"))]
use uds::{UnixListenerExt, UnixSocketAddr, UnixStreamExt};
const ASHMEM_SERVER_NAME: &str = "@ashmem_server";
/// The default server name for our abstract shmem server
#[cfg(all(unix, not(any(target_os = "ios", target_os = "macos"))))]
const UNIX_SERVER_NAME: &str = "@libafl_unix_shmem_server";
/// `MacOS` server name is on disk, since `MacOS` doesn't support abtract domain sockets.
#[cfg(any(target_os = "ios", target_os = "macos"))]
const UNIX_SERVER_NAME: &str = "./libafl_unix_shmem_server";
/// Hands out served shared maps, as used on Android.
#[derive(Debug)]
pub struct ServedShMemProvider {
pub struct ServedShMemProvider<SP> {
stream: UnixStream,
inner: AshmemShMemProvider,
inner: SP,
id: i32,
}
/// [`ShMem`] that got served from a [`AshmemService`] via domain sockets and can now be used in this program.
/// It works around Android's lack of "proper" shared maps.
#[derive(Clone, Debug)]
pub struct ServedShMem {
inner: ManuallyDrop<AshmemShMem>,
pub struct ServedShMem<SH>
where
SH: ShMem,
{
inner: ManuallyDrop<SH>,
server_fd: i32,
}
impl ShMem for ServedShMem {
impl<SH> ShMem for ServedShMem<SH>
where
SH: ShMem,
{
fn id(&self) -> ShMemId {
let client_id = self.inner.id();
ShMemId::from_string(&format!("{}:{}", self.server_fd, client_id.to_string()))
@ -73,10 +85,10 @@ impl ShMem for ServedShMem {
}
}
impl ServedShMemProvider {
impl<SP> ServedShMemProvider<SP> {
/// Send a request to the server, and wait for a response
#[allow(clippy::similar_names)] // id and fd
fn send_receive(&mut self, request: AshmemRequest) -> Result<(i32, i32), Error> {
fn send_receive(&mut self, request: ServedShMemRequest) -> Result<(i32, i32), Error> {
let body = postcard::to_allocvec(&request)?;
let header = (body.len() as u32).to_be_bytes();
@ -99,34 +111,43 @@ impl ServedShMemProvider {
}
}
impl Default for ServedShMemProvider {
impl<SP> Default for ServedShMemProvider<SP>
where
SP: ShMemProvider,
{
fn default() -> Self {
Self::new().unwrap()
}
}
impl Clone for ServedShMemProvider {
impl<SP> Clone for ServedShMemProvider<SP>
where
SP: ShMemProvider,
{
fn clone(&self) -> Self {
Self::new().unwrap()
}
}
impl ShMemProvider for ServedShMemProvider {
type Mem = ServedShMem;
impl<SP> ShMemProvider for ServedShMemProvider<SP>
where
SP: ShMemProvider,
{
type Mem = ServedShMem<SP::Mem>;
/// Connect to the server and return a new [`ServedShMemProvider`]
fn new() -> Result<Self, Error> {
let mut res = Self {
stream: UnixStream::connect_to_unix_addr(&UnixSocketAddr::new(ASHMEM_SERVER_NAME)?)?,
inner: AshmemShMemProvider::new()?,
stream: UnixStream::connect_to_unix_addr(&UnixSocketAddr::new(UNIX_SERVER_NAME)?)?,
inner: SP::new()?,
id: -1,
};
let (id, _) = res.send_receive(AshmemRequest::Hello(None))?;
let (id, _) = res.send_receive(ServedShMemRequest::Hello(None))?;
res.id = id;
Ok(res)
}
fn new_map(&mut self, map_size: usize) -> Result<Self::Mem, crate::Error> {
let (server_fd, client_fd) = self.send_receive(AshmemRequest::NewMap(map_size))?;
let (server_fd, client_fd) = self.send_receive(ServedShMemRequest::NewMap(map_size))?;
Ok(ServedShMem {
inner: ManuallyDrop::new(
@ -140,7 +161,7 @@ impl ShMemProvider for ServedShMemProvider {
fn from_id_and_size(&mut self, id: ShMemId, size: usize) -> Result<Self::Mem, Error> {
let parts = id.as_str().split(':').collect::<Vec<&str>>();
let server_id_str = parts.get(0).unwrap();
let (server_fd, client_fd) = self.send_receive(AshmemRequest::ExistingMap(
let (server_fd, client_fd) = self.send_receive(ServedShMemRequest::ExistingMap(
ShMemDescription::from_string_and_size(server_id_str, size),
))?;
Ok(ServedShMem {
@ -156,8 +177,8 @@ impl ShMemProvider for ServedShMemProvider {
if is_child {
// After fork, the child needs to reconnect as to not share the fds with the parent.
self.stream =
UnixStream::connect_to_unix_addr(&UnixSocketAddr::new(ASHMEM_SERVER_NAME)?)?;
let (id, _) = self.send_receive(AshmemRequest::Hello(Some(self.id)))?;
UnixStream::connect_to_unix_addr(&UnixSocketAddr::new(UNIX_SERVER_NAME)?)?;
let (id, _) = self.send_receive(ServedShMemRequest::Hello(Some(self.id)))?;
self.id = id;
}
Ok(())
@ -165,8 +186,8 @@ impl ShMemProvider for ServedShMemProvider {
fn release_map(&mut self, map: &mut Self::Mem) {
let (refcount, _) = self
.send_receive(AshmemRequest::Deregister(map.server_fd))
.expect("Could not communicate with AshMem server!");
.send_receive(ServedShMemRequest::Deregister(map.server_fd))
.expect("Could not communicate with ServedShMem server!");
if refcount == 1 {
unsafe {
ManuallyDrop::drop(&mut map.inner);
@ -177,7 +198,7 @@ impl ShMemProvider for ServedShMemProvider {
/// A request sent to the [`ShMem`] server to receive a fd to a shared map
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub enum AshmemRequest {
pub enum ServedShMemRequest {
/// Register a new map with a given size.
NewMap(usize),
/// Another client already has a map with this description mapped.
@ -187,15 +208,23 @@ pub enum AshmemRequest {
/// A message that tells us hello, and optionally which other client we were created from, we
/// return a client id.
Hello(Option<i32>),
/// The ShMem Service should exit. This is sually sent internally on `drop`, but feel free to do whatever with it?
Exit,
}
#[derive(Debug)]
struct AshmemClient {
struct SharedShMemClient<SH>
where
SH: ShMem,
{
stream: UnixStream,
maps: HashMap<i32, Vec<Rc<RefCell<AshmemShMem>>>>,
maps: HashMap<i32, Vec<Rc<RefCell<SH>>>>,
}
impl AshmemClient {
impl<SH> SharedShMemClient<SH>
where
SH: ShMem,
{
fn new(stream: UnixStream) -> Self {
Self {
stream,
@ -207,37 +236,134 @@ impl AshmemClient {
/// The [`AshmemService`] is a service handing out [`ShMem`] pages via unix domain sockets.
/// It is mainly used and needed on Android.
#[derive(Debug)]
pub struct AshmemService {
provider: AshmemShMemProvider,
clients: HashMap<RawFd, AshmemClient>,
all_maps: HashMap<i32, Weak<RefCell<AshmemShMem>>>,
pub struct ShMemService<SP>
where
SP: ShMemProvider,
{
join_handle: Option<JoinHandle<Result<(), Error>>>,
phantom: PhantomData<*const SP>,
}
#[derive(Debug)]
enum AshmemResponse {
Mapping(Rc<RefCell<AshmemShMem>>),
enum ServedShMemResponse<SP>
where
SP: ShMemProvider,
{
Mapping(Rc<RefCell<SP::Mem>>),
Id(i32),
RefCount(u32),
}
impl AshmemService {
/// Create a new [`AshMem`] service
impl<SP> ShMemService<SP>
where
SP: ShMemProvider,
{
/// Create a new [`ShMemService`], then listen and service incoming connections in a new thread.
pub fn start() -> Result<Self, Error> {
println!("Starting ShMemService");
#[allow(clippy::mutex_atomic)]
let syncpair = Arc::new((Mutex::new(false), Condvar::new()));
let childsyncpair = Arc::clone(&syncpair);
let join_handle = thread::spawn(move || {
println!("Thread...");
let mut worker = match ServedShMemServiceWorker::<SP>::new() {
Ok(worker) => worker,
Err(e) => {
// Make sure the parent processes can continue
let (lock, cvar) = &*childsyncpair;
*lock.lock().unwrap() = true;
cvar.notify_one();
println!("Error creating ShMemService: {:?}", e);
return Err(e);
}
};
if let Err(e) = worker.listen(UNIX_SERVER_NAME, &childsyncpair) {
println!("Error spawning ShMemService: {:?}", e);
Err(e)
} else {
Ok(())
}
});
let (lock, cvar) = &*syncpair;
let mut started = lock.lock().unwrap();
while !*started {
started = cvar.wait(started).unwrap();
}
Ok(Self {
join_handle: Some(join_handle),
phantom: PhantomData,
})
}
}
impl<SP> Drop for ShMemService<SP>
where
SP: ShMemProvider,
{
fn drop(&mut self) {
let join_handle = self.join_handle.take();
// TODO: Guess we could use the `cvar` // Mutex here instead?
if let Some(join_handle) = join_handle {
let mut stream = match UnixStream::connect_to_unix_addr(
&UnixSocketAddr::new(UNIX_SERVER_NAME).unwrap(),
) {
Ok(stream) => stream,
Err(_) => return, // ignoring non-started server
};
let body = postcard::to_allocvec(&ServedShMemRequest::Exit).unwrap();
let header = (body.len() as u32).to_be_bytes();
let mut message = header.to_vec();
message.extend(body);
stream
.write_all(&message)
.expect("Failed to send bye-message to ShMemService");
join_handle
.join()
.expect("Failed to join ShMemService thread!")
.expect("Error in ShMemService thread!");
}
}
}
/// The struct for the worker, handling incoming requests for [`ShMem`].
struct ServedShMemServiceWorker<SP>
where
SP: ShMemProvider,
{
provider: SP,
clients: HashMap<RawFd, SharedShMemClient<SP::Mem>>,
all_maps: HashMap<i32, Weak<RefCell<SP::Mem>>>,
}
impl<SP> ServedShMemServiceWorker<SP>
where
SP: ShMemProvider,
{
/// Create a new [`ShMemService`]
fn new() -> Result<Self, Error> {
Ok(AshmemService {
provider: AshmemShMemProvider::new()?,
Ok(Self {
provider: SP::new()?,
clients: HashMap::new(),
all_maps: HashMap::new(),
})
}
/// Read and handle the client request, send the answer over unix fd.
fn handle_request(&mut self, client_id: RawFd) -> Result<AshmemResponse, Error> {
fn handle_request(&mut self, client_id: RawFd) -> Result<ServedShMemResponse<SP>, Error> {
let request = self.read_request(client_id)?;
//println!("got ashmem client: {}, request:{:?}", client_id, request);
// Handle the client request
let response = match request {
AshmemRequest::Hello(other_id) => {
ServedShMemRequest::Hello(other_id) => {
if let Some(other_id) = other_id {
if other_id != client_id {
// remove temporarily
@ -249,21 +375,21 @@ impl AshmemService {
self.clients.insert(other_id, other_client.unwrap());
}
};
Ok(AshmemResponse::Id(client_id))
Ok(ServedShMemResponse::Id(client_id))
}
AshmemRequest::NewMap(map_size) => {
ServedShMemRequest::NewMap(map_size) => {
let new_map = self.provider.new_map(map_size)?;
let description = new_map.description();
let new_rc = Rc::new(RefCell::new(new_map));
self.all_maps
.insert(description.id.into(), Rc::downgrade(&new_rc));
Ok(AshmemResponse::Mapping(new_rc))
Ok(ServedShMemResponse::Mapping(new_rc))
}
AshmemRequest::ExistingMap(description) => {
ServedShMemRequest::ExistingMap(description) => {
let client = self.clients.get_mut(&client_id).unwrap();
let description_id: i32 = description.id.into();
if client.maps.contains_key(&description_id) {
Ok(AshmemResponse::Mapping(
Ok(ServedShMemResponse::Mapping(
client
.maps
.get_mut(&description_id)
@ -275,7 +401,7 @@ impl AshmemService {
.clone(),
))
} else {
Ok(AshmemResponse::Mapping(
Ok(ServedShMemResponse::Mapping(
self.all_maps
.get_mut(&description_id)
.unwrap()
@ -285,24 +411,29 @@ impl AshmemService {
))
}
}
AshmemRequest::Deregister(map_id) => {
ServedShMemRequest::Deregister(map_id) => {
let client = self.clients.get_mut(&client_id).unwrap();
let maps = client.maps.entry(map_id).or_default();
if maps.is_empty() {
Ok(AshmemResponse::RefCount(0u32))
Ok(ServedShMemResponse::RefCount(0u32))
} else {
Ok(AshmemResponse::RefCount(
Ok(ServedShMemResponse::RefCount(
Rc::strong_count(&maps.pop().unwrap()) as u32,
))
}
}
ServedShMemRequest::Exit => {
println!("ShMemService - Exiting");
// stopping the server
return Err(Error::ShuttingDown);
}
};
//println!("send ashmem client: {}, response: {:?}", client_id, &response);
response
}
fn read_request(&mut self, client_id: RawFd) -> Result<AshmemRequest, Error> {
fn read_request(&mut self, client_id: RawFd) -> Result<ServedShMemRequest, Error> {
let client = self.clients.get_mut(&client_id).unwrap();
// Always receive one be u32 of size, then the command.
@ -315,7 +446,7 @@ impl AshmemService {
.stream
.read_exact(&mut bytes)
.expect("Failed to read message body");
let request: AshmemRequest = postcard::from_bytes(&bytes)?;
let request: ServedShMemRequest = postcard::from_bytes(&bytes)?;
Ok(request)
}
@ -323,7 +454,7 @@ impl AshmemService {
let response = self.handle_request(client_id)?;
match response {
AshmemResponse::Mapping(mapping) => {
ServedShMemResponse::Mapping(mapping) => {
let id = mapping.borrow().id();
let server_fd: i32 = id.to_string().parse().unwrap();
let client = self.clients.get_mut(&client_id).unwrap();
@ -332,11 +463,11 @@ impl AshmemService {
.send_fds(id.to_string().as_bytes(), &[server_fd])?;
client.maps.entry(server_fd).or_default().push(mapping);
}
AshmemResponse::Id(id) => {
ServedShMemResponse::Id(id) => {
let client = self.clients.get_mut(&client_id).unwrap();
client.stream.send_fds(id.to_string().as_bytes(), &[])?;
}
AshmemResponse::RefCount(refcount) => {
ServedShMemResponse::RefCount(refcount) => {
let client = self.clients.get_mut(&client_id).unwrap();
client
.stream
@ -346,23 +477,6 @@ impl AshmemService {
Ok(())
}
/// Create a new [`AshmemService`], then listen and service incoming connections in a new thread.
pub fn start() -> Result<thread::JoinHandle<Result<(), Error>>, Error> {
#[allow(clippy::mutex_atomic)]
let syncpair = Arc::new((Mutex::new(false), Condvar::new()));
let childsyncpair = Arc::clone(&syncpair);
let join_handle =
thread::spawn(move || Self::new()?.listen(ASHMEM_SERVER_NAME, &childsyncpair));
let (lock, cvar) = &*syncpair;
let mut started = lock.lock().unwrap();
while !*started {
started = cvar.wait(started).unwrap();
}
Ok(join_handle)
}
/// Listen on a filename (or abstract name) for new connections and serve them. This function
/// should not return.
fn listen(
@ -378,10 +492,13 @@ impl AshmemService {
let (lock, cvar) = &**syncpair;
*lock.lock().unwrap() = true;
cvar.notify_one();
println!("Error in ShMem Worker");
return Err(Error::Unknown(
"The server appears to already be running. We are probably a client".to_string(),
));
};
let mut poll_fds: Vec<PollFd> = vec![PollFd::new(
listener.as_raw_fd(),
PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLRDBAND,
@ -418,7 +535,7 @@ impl AshmemService {
}
};
} else {
let (stream, addr) = match listener.accept_unix_addr() {
let (stream, _addr) = match listener.accept_unix_addr() {
Ok(stream_val) => stream_val,
Err(e) => {
println!("Error accepting client: {:?}", e);
@ -426,17 +543,21 @@ impl AshmemService {
}
};
println!("Recieved connection from {:?}", addr);
// println!("Recieved connection from {:?}", addr);
let pollfd = PollFd::new(
stream.as_raw_fd(),
PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLRDBAND,
);
poll_fds.push(pollfd);
let client = AshmemClient::new(stream);
let client = SharedShMemClient::new(stream);
let client_id = client.stream.as_raw_fd();
self.clients.insert(client_id, client);
match self.handle_client(client_id) {
Ok(()) => (),
Err(Error::ShuttingDown) => {
println!("Shutting down");
return Ok(());
}
Err(e) => {
dbg!("Ignoring failed read from client", e);
}
@ -449,3 +570,14 @@ impl AshmemService {
}
}
}
impl<SP> Drop for ServedShMemServiceWorker<SP>
where
SP: ShMemProvider,
{
fn drop(&mut self) {
// try to remove the file from fs, and ignore errors.
#[cfg(target_os = "macos")]
drop(fs::remove_file(&UNIX_SERVER_NAME));
}
}

View File

@ -7,38 +7,58 @@ use core::{
fmt::{self, Debug, Display},
mem::ManuallyDrop,
};
#[cfg(all(feature = "std", unix, not(target_os = "android")))]
pub use unix_shmem::{MmapShMem, MmapShMemProvider};
#[cfg(all(feature = "std", unix))]
pub use unix_shmem::{UnixShMem, UnixShMemProvider};
/// The default [`ShMemProvider`] for this os.
use crate::Error;
#[cfg(all(feature = "std", unix))]
pub type OsShMemProvider = UnixShMemProvider;
/// The default [`ShMem`] for this os.
#[cfg(all(feature = "std", unix))]
pub type OsShMem = UnixShMem;
pub use crate::bolts::os::unix_shmem_server::{ServedShMemProvider, ShMemService};
#[cfg(all(windows, feature = "std"))]
pub use win32_shmem::{Win32ShMem, Win32ShMemProvider};
#[cfg(all(windows, feature = "std"))]
pub type OsShMemProvider = Win32ShMemProvider;
pub type StdShMemProvider = Win32ShMemProvider;
#[cfg(all(windows, feature = "std"))]
pub type OsShMem = Win32ShMem;
use crate::Error;
pub type StdShMem = Win32ShMem;
#[cfg(all(target_os = "android", feature = "std"))]
use crate::bolts::os::ashmem_server::ServedShMemProvider;
pub type StdShMemProvider = RcShMemProvider<ServedShMemProvider<AshmemShMemProvider>>;
#[cfg(all(target_os = "android", feature = "std"))]
pub type StdShMemProvider = RcShMemProvider<ServedShMemProvider>;
pub type StdShMem = RcShMem<ServedShMem<AshmemShMem>>;
#[cfg(all(target_os = "android", feature = "std"))]
pub type StdShMem = RcShMem<ServedShMemProvider>;
pub type StdShMemService = ShMemService<AshmemShMemProvider>;
#[cfg(all(feature = "std", any(target_os = "ios", target_os = "macos")))]
pub type StdShMemProvider = RcShMemProvider<ServedShMemProvider<MmapShMemProvider>>;
#[cfg(all(feature = "std", any(target_os = "ios", target_os = "macos")))]
pub type StdShMem = RcShMem<ServedShMem<MmapShMem>>;
#[cfg(all(feature = "std", any(target_os = "ios", target_os = "macos")))]
pub type StdShMemService = ShMemService<MmapShMemProvider>;
/// The default [`ShMemProvider`] for this os.
#[cfg(all(feature = "std", not(target_os = "android")))]
pub type StdShMemProvider = OsShMemProvider;
/// The default [`ShMem`] for this os.
#[cfg(all(feature = "std", not(target_os = "android")))]
pub type StdShMem = OsShMem;
#[cfg(all(
feature = "std",
unix,
not(any(target_os = "android", target_os = "ios", target_os = "macos"))
))]
pub type StdShMemProvider = UnixShMemProvider;
/// The default [`ShMemProvider`] for this os.
#[cfg(all(
feature = "std",
unix,
not(any(target_os = "android", target_os = "ios", target_os = "macos"))
))]
pub type StdShMem = UnixShMem;
#[cfg(any(
not(any(target_os = "android", target_os = "macos", target_os = "ios")),
not(feature = "std")
))]
pub type StdShMemService = DummyShMemService;
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
@ -47,6 +67,12 @@ use std::{
env,
};
#[cfg(all(
unix,
feature = "std",
any(target_os = "ios", target_os = "macos", target_os = "android")
))]
use super::os::unix_shmem_server::ServedShMem;
#[cfg(all(unix, feature = "std"))]
use crate::bolts::os::pipes::Pipe;
#[cfg(all(unix, feature = "std"))]
@ -436,14 +462,13 @@ where
/// A Unix sharedmem implementation.
///
/// On Android, this is partially reused to wrap [`unix_shmem::ashmem::AshmemShMem`],
/// Although for an [`unix_shmem::ashmem::AshmemShMemProvider`] using a unix domain socket
/// Although for an [`unix_shmem::ashmem::ServedShMemProvider`] using a unix domain socket
/// Is needed on top.
#[cfg(all(unix, feature = "std"))]
pub mod unix_shmem {
/// Shared memory provider for Android, allocating and forwarding maps over unix domain sockets.
#[cfg(target_os = "android")]
pub type UnixShMemProvider = ashmem::AshmemShMemProvider;
pub type UnixShMemProvider = ashmem::ServedShMemProvider;
/// Shared memory for Android
#[cfg(target_os = "android")]
pub type UnixShMem = ashmem::AshmemShMem;
@ -454,10 +479,22 @@ pub mod unix_shmem {
#[cfg(not(target_os = "android"))]
pub type UnixShMem = ashmem::AshmemShMem;
/// Mmap [`ShMem`] for Unix
#[cfg(not(target_os = "android"))]
pub use default::MmapShMem;
/// Mmap [`ShMemProvider`] for Unix
#[cfg(not(target_os = "android"))]
pub use default::MmapShMemProvider;
#[cfg(all(unix, feature = "std", not(target_os = "android")))]
mod default {
use core::{ptr, slice};
use libc::{c_int, c_long, c_uchar, c_uint, c_ulong, c_ushort, c_void};
use core::{convert::TryInto, ptr, slice};
use libc::{
c_int, c_long, c_uchar, c_uint, c_ulong, c_ushort, c_void, close, ftruncate, mmap,
munmap, perror, shm_open, shm_unlink,
};
use std::{io::Write, process, ptr::null_mut};
use crate::{
bolts::shmem::{ShMem, ShMemId, ShMemProvider},
@ -502,6 +539,197 @@ pub mod unix_shmem {
fn shmat(__shmid: c_int, __shmaddr: *const c_void, __shmflg: c_int) -> *mut c_void;
}
const MAX_MMAP_FILENAME_LEN: usize = 256;
/// 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
/// shared mem segments for dubious Mach kernel reasons.
#[derive(Clone, Debug)]
pub struct MmapShMem {
/// The path of this shared memory segment.
/// None in case we didn't [`shm_open`] this ourselves, but someone sent us the FD.
filename_path: Option<[u8; MAX_MMAP_FILENAME_LEN]>,
/// The size of this map
map_size: usize,
/// The map ptr
map: *mut u8,
/// The shmem id, containing the file descriptor and size, to send over the wire
id: ShMemId,
/// The file descriptor of the shmem
shm_fd: c_int,
}
impl MmapShMem {
pub fn new(map_size: usize, shmem_ctr: usize) -> Result<Self, Error> {
unsafe {
let mut filename_path = [0_u8; MAX_MMAP_FILENAME_LEN];
write!(
&mut filename_path[..MAX_MMAP_FILENAME_LEN - 1],
"/libafl_{}_{}",
process::id(),
shmem_ctr
)?;
/* 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 {
perror(b"shm_open\0".as_ptr() as *const _);
return Err(Error::Unknown(format!(
"Failed to shm_open map with id {:?}",
shmem_ctr
)));
}
/* configure the size of the shared memory segment */
if ftruncate(shm_fd, map_size.try_into()?) != 0 {
perror(b"ftruncate\0".as_ptr() as *const _);
shm_unlink(filename_path.as_ptr() as *const _);
return Err(Error::Unknown(format!(
"setup_shm(): ftruncate() failed for map with id {:?}",
shmem_ctr
)));
}
/* map the shared memory segment to the address space of the process */
let map = mmap(
null_mut(),
map_size,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_SHARED,
shm_fd,
0,
);
if map == libc::MAP_FAILED || map.is_null() {
perror(b"mmap\0".as_ptr() as *const _);
close(shm_fd);
shm_unlink(filename_path.as_ptr() as *const _);
return Err(Error::Unknown(format!(
"mmap() failed for map with id {:?}",
shmem_ctr
)));
}
Ok(Self {
filename_path: Some(filename_path),
map: map as *mut u8,
map_size,
shm_fd,
id: ShMemId::from_string(&format!("{}", shm_fd)),
})
}
}
fn from_id_and_size(id: ShMemId, map_size: usize) -> Result<Self, Error> {
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(
null_mut(),
map_size,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_SHARED,
shm_fd,
0,
);
if map == libc::MAP_FAILED || map.is_null() {
perror(b"mmap\0".as_ptr() as *const _);
close(shm_fd);
return Err(Error::Unknown(format!(
"mmap() failed for map with fd {:?}",
shm_fd
)));
}
Ok(Self {
filename_path: None,
map: map as *mut u8,
map_size,
shm_fd,
id: ShMemId::from_string(&format!("{}", shm_fd)),
})
}
}
}
/// A [`ShMemProvider`] which uses `shmget`/`shmat`/`shmctl` to provide shared memory mappings.
#[cfg(unix)]
#[derive(Clone, Debug)]
pub struct MmapShMemProvider {
current_map_id: usize,
}
unsafe impl Send for MmapShMemProvider {}
#[cfg(unix)]
impl Default for MmapShMemProvider {
fn default() -> Self {
Self::new().unwrap()
}
}
/// Implement [`ShMemProvider`] for [`UnixShMemProvider`].
#[cfg(unix)]
impl ShMemProvider for MmapShMemProvider {
type Mem = MmapShMem;
fn new() -> Result<Self, Error> {
Ok(Self { current_map_id: 0 })
}
fn new_map(&mut self, map_size: usize) -> Result<Self::Mem, Error> {
self.current_map_id += 1;
MmapShMem::new(map_size, self.current_map_id)
}
fn from_id_and_size(&mut self, id: ShMemId, size: usize) -> Result<Self::Mem, Error> {
MmapShMem::from_id_and_size(id, size)
}
}
impl ShMem for MmapShMem {
fn id(&self) -> ShMemId {
self.id
}
fn len(&self) -> usize {
self.map_size
}
fn map(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.map, self.map_size) }
}
fn map_mut(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.map, self.map_size) }
}
}
impl Drop for MmapShMem {
fn drop(&mut self) {
unsafe {
if self.map.is_null() {
panic!("Map should never be null for MmapShMem (on Drop)");
}
munmap(self.map as *mut _, self.map_size);
self.map = ptr::null_mut();
if self.shm_fd == -1 {
panic!("FD should never be -1 for MmapShMem (on Drop)");
}
// 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 _);
}
}
}
}
/// The default sharedmap impl for unix using shmctl & shmget
#[derive(Clone, Debug)]
pub struct CommonUnixShMem {
@ -514,7 +742,11 @@ pub mod unix_shmem {
/// Create a new shared memory mapping, using shmget/shmat
pub fn new(map_size: usize) -> Result<Self, Error> {
unsafe {
let os_id = shmget(0, map_size as c_ulong, 0o1000 | 0o2000 | 0o600);
let os_id = shmget(
libc::IPC_PRIVATE,
map_size as c_ulong,
libc::IPC_CREAT | libc::IPC_EXCL | libc::SHM_R | libc::SHM_W,
);
if os_id < 0_i32 {
return Err(Error::Unknown(format!("Failed to allocate a shared mapping of size {} - check OS limits (i.e shmall, shmmax)", map_size)));
@ -523,7 +755,7 @@ pub mod unix_shmem {
let map = shmat(os_id, ptr::null(), 0) as *mut c_uchar;
if map as c_int == -1 || map.is_null() {
shmctl(os_id, 0, ptr::null_mut());
shmctl(os_id, libc::IPC_RMID, ptr::null_mut());
return Err(Error::Unknown(
"Failed to map the shared mapping".to_string(),
));
@ -543,7 +775,7 @@ pub mod unix_shmem {
let id_int: i32 = id.into();
let map = shmat(id_int, ptr::null(), 0) as *mut c_uchar;
if map == usize::MAX as *mut c_void as *mut c_uchar || map.is_null() {
if map.is_null() || map == null_mut::<c_uchar>().wrapping_sub(1) {
return Err(Error::Unknown(
"Failed to map the shared mapping".to_string(),
));
@ -579,7 +811,7 @@ pub mod unix_shmem {
fn drop(&mut self) {
unsafe {
let id_int: i32 = self.id.into();
shmctl(id_int, 0, ptr::null_mut());
shmctl(id_int, libc::IPC_RMID, ptr::null_mut());
}
}
}
@ -999,12 +1231,28 @@ pub mod win32_shmem {
}
}
/// A `ShMemService` dummy, that does nothing on start.
/// Drop in for targets that don't need a server for ref counting and page creation.
#[derive(Debug)]
pub struct DummyShMemService;
impl DummyShMemService {
/// Create a new [`DummyShMemService`] that does nothing.
/// Useful only to have the same API for [`StdShMemService`] on Operating Systems that don't need it.
#[inline]
pub fn start() -> Result<Self, Error> {
Ok(Self {})
}
}
#[cfg(feature = "std")]
/// A cursor around [`ShMem`] that immitates [`std::io::Cursor`]. Notably, this implements [`Write`] for [`ShMem`] in std environments.
pub struct ShMemCursor<T: ShMem> {
inner: T,
pos: usize,
}
#[cfg(feature = "std")]
impl<T: ShMem> ShMemCursor<T> {
pub fn new(shmem: T) -> Self {
Self {
@ -1083,3 +1331,22 @@ impl<T: ShMem> std::io::Seek for ShMemCursor<T> {
Ok(effective_new_pos)
}
}
#[cfg(feature = "std")]
#[cfg(test)]
mod tests {
use serial_test::serial;
use crate::bolts::shmem::{ShMem, ShMemProvider, StdShMemProvider, StdShMemService};
#[test]
#[serial]
fn test_shmem_service() {
#[allow(unused_variables)]
let service = StdShMemService::start().unwrap();
let mut provider = StdShMemProvider::new().unwrap();
let mut map = provider.new_map(1024).unwrap();
map.map_mut()[0] = 1;
assert!(map.map()[0] == 1);
}
}

View File

@ -111,7 +111,8 @@ where
if size_of::<StateShMemContent>() + serialized.len() > self.shmem.len() {
// generate a filename
let mut hasher = AHasher::new_with_keys(0, 0);
hasher.write(&serialized[serialized.len() - 1024..]);
// Using the last few k as randomness for a filename, hoping it's unique.
hasher.write(&serialized[serialized.len().saturating_sub(4096)..]);
let filename = format!("{:016x}.libafl_state", hasher.finish());
let tmpfile = temp_dir().join(&filename);
@ -238,15 +239,20 @@ where
#[cfg(test)]
mod tests {
use serial_test::serial;
use crate::bolts::{
shmem::{ShMemProvider, StdShMemProvider},
shmem::{ShMemProvider, StdShMemProvider, StdShMemService},
staterestore::StateRestorer,
};
#[test]
#[serial]
fn test_state_restore() {
const TESTMAP_SIZE: usize = 1024;
let _service = StdShMemService::start().unwrap();
let mut shmem_provider = StdShMemProvider::new().unwrap();
let shmem = shmem_provider.new_map(TESTMAP_SIZE).unwrap();
let mut state_restorer = StateRestorer::<StdShMemProvider>::new(shmem);

View File

@ -15,7 +15,7 @@ use std::net::{SocketAddr, ToSocketAddrs};
#[cfg(feature = "std")]
use crate::bolts::{
llmp::{LlmpClient, LlmpConnection},
shmem::StdShMemProvider,
shmem::{StdShMemProvider, StdShMemService},
staterestore::StateRestorer,
};
@ -49,7 +49,7 @@ use crate::bolts::os::startable_self;
use crate::bolts::os::{fork, ForkResult};
#[cfg(all(target_os = "android", feature = "std"))]
use crate::bolts::os::ashmem_server::AshmemService;
use crate::bolts::os::unix_shmem_server::ShMemService;
#[cfg(feature = "std")]
use typed_builder::TypedBuilder;
@ -689,8 +689,7 @@ where
OT: ObserversTuple<I, S> + serde::de::DeserializeOwned,
S: DeserializeOwned,
{
#[cfg(target_os = "android")]
AshmemService::start().expect("Error starting Ashmem Service");
let _service = StdShMemService::start().expect("Error starting ShMem Service");
RestartingMgr::builder()
.shmem_provider(StdShMemProvider::new()?)
@ -929,11 +928,13 @@ where
#[cfg(test)]
#[cfg(feature = "std")]
mod tests {
use serial_test::serial;
use crate::{
bolts::{
llmp::{LlmpClient, LlmpSharedMap},
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
shmem::{ShMemProvider, StdShMemProvider, StdShMemService},
staterestore::StateRestorer,
tuples::tuple_list,
},
@ -949,7 +950,10 @@ mod tests {
use core::sync::atomic::{compiler_fence, Ordering};
#[test]
#[serial]
fn test_mgr_state_restore() {
let _service = StdShMemService::start().unwrap();
let rand = StdRand::with_seed(0);
let mut corpus = InMemoryCorpus::<BytesInput>::new();

View File

@ -3,6 +3,7 @@ use core::marker::PhantomData;
#[cfg(feature = "std")]
use std::{process::Child, time::Duration};
#[cfg(feature = "std")]
use crate::{
executors::{Executor, ExitKind, HasObservers},
inputs::Input,

View File

@ -614,9 +614,11 @@ where
#[cfg(test)]
mod tests {
use serial_test::serial;
use crate::{
bolts::{
shmem::{ShMem, ShMemProvider, StdShMemProvider},
shmem::{ShMem, ShMemProvider, StdShMemProvider, StdShMemService},
tuples::tuple_list,
},
executors::ForkserverExecutor,
@ -625,11 +627,14 @@ mod tests {
Error,
};
#[test]
#[serial]
fn test_forkserver() {
const MAP_SIZE: usize = 65536;
let bin = "echo";
let args = vec![String::from("@@")];
let _service = StdShMemService::start().unwrap();
let mut shmem = StdShMemProvider::new()
.unwrap()
.new_map(MAP_SIZE as usize)

View File

@ -19,7 +19,9 @@ pub use shadow::ShadowExecutor;
pub mod with_observers;
pub use with_observers::WithObservers;
#[cfg(feature = "std")]
pub mod command;
#[cfg(feature = "std")]
pub use command::CommandExecutor;
use crate::{

View File

@ -107,7 +107,12 @@ impl<'a> FridaHelper<'a> for FridaInstrumentationHelper<'a> {
self.asan_runtime.register_thread();
}
#[cfg(not(target_arch = "aarch64"))]
fn pre_exec<I: Input + HasTargetBytes>(&mut self, _input: &I) {}
#[cfg(target_arch = "aarch64")]
fn pre_exec<I: Input + HasTargetBytes>(&mut self, input: &I) {
#[cfg(target_arch = "aarch64")]
let target_bytes = input.target_bytes();
let slice = target_bytes.as_slice();
//println!("target_bytes: {:#x}: {:02x?}", slice.as_ptr() as usize, slice);

View File

@ -71,7 +71,7 @@ impl<'a, H> InMemoryBytesCoverageSugar<'a, H>
where
H: FnMut(&[u8]),
{
#[allow(clippy::too_many_lines)]
#[allow(clippy::too_many_lines, clippy::similar_names)]
pub fn run(&mut self) {
let conf = self
.configuration

View File

@ -7,7 +7,7 @@ use libafl::{
current_nanos,
launcher::Launcher,
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
shmem::{ShMemProvider, StdShMemProvider, StdShMemService},
tuples::{tuple_list, Merge},
},
corpus::{

View File

@ -1,7 +1,7 @@
#!/bin/sh
echo "Warning: this script is not a proper fix to do LLMP fuzzing." \
"Instead, run `afl-persistent-config` with SIP disabled."
'Instead, run `afl-persistent-config` with SIP disabled.'
sudo sysctl -w kern.sysv.shmmax=524288000
sudo sysctl -w kern.sysv.shmmin=1