diff --git a/fuzzers/libfuzzer_libpng/src/fuzzer.rs b/fuzzers/libfuzzer_libpng/src/fuzzer.rs index 62845e7799..35123a5611 100644 --- a/fuzzers/libfuzzer_libpng/src/fuzzer.rs +++ b/fuzzers/libfuzzer_libpng/src/fuzzer.rs @@ -74,8 +74,17 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> // The restarting state will spawn the same process again as child, then restarted it each time it crashes. let (state, mut restarting_mgr) = - setup_restarting_mgr::<_, _, UnixShMem, _>(stats, broker_port) - .expect("Failed to setup the restarter".into()); + match setup_restarting_mgr::<_, _, UnixShMem, _>(stats, broker_port) { + Ok(res) => res, + Err(err) => match err { + Error::ShuttingDown => { + return Ok(()); + } + _ => { + panic!("Failed to setup the restarter: {}", err); + } + }, + }; // Create an observation channel using the coverage map let edges_observer = HitcountsMapObserver::new(StdMapObserver::new_from_ptr( diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 7c7f9f5e00..e521f99128 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -57,6 +57,7 @@ serde_json = { version = "1.0", optional = true, default-features = false, featu [target.'cfg(unix)'.dependencies] libc = "0.2" # For (*nix) libc +nix = "0.20.0" [target.'cfg(windows)'.dependencies] windows = "0.3.1" diff --git a/libafl/examples/llmp_test/main.rs b/libafl/examples/llmp_test/main.rs index 139030a833..5093dd468f 100644 --- a/libafl/examples/llmp_test/main.rs +++ b/libafl/examples/llmp_test/main.rs @@ -96,9 +96,9 @@ fn main() { "broker" => { let mut broker = llmp::LlmpBroker::::new().unwrap(); broker - .launch_tcp_listener( + .launch_listener(llmp::Listener::Tcp( std::net::TcpListener::bind(format!("127.0.0.1:{}", port)).unwrap(), - ) + )) .unwrap(); broker.loop_forever(&mut broker_message_hook, Some(Duration::from_millis(5))) } diff --git a/libafl/src/bolts/llmp.rs b/libafl/src/bolts/llmp.rs index 1daf42db52..edba182484 100644 --- a/libafl/src/bolts/llmp.rs +++ b/libafl/src/bolts/llmp.rs @@ -52,7 +52,7 @@ Then register some clientloops using llmp_broker_register_threaded_clientloop */ -use alloc::vec::Vec; +use alloc::{string::String, vec::Vec}; use core::{ cmp::max, fmt::Debug, @@ -64,14 +64,42 @@ use core::{ use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] use std::{ - env, + env, fs, io::{Read, Write}, + mem::zeroed, net::{TcpListener, TcpStream}, thread, }; -use super::shmem::{ShMem, ShMemDescription}; -use crate::Error; +#[cfg(all(feature = "std", unix))] +use nix::{ + cmsg_space, + sys::{ + socket::{recvmsg, sendmsg, ControlMessage, ControlMessageOwned, MsgFlags}, + uio::IoVec, + }, +}; +#[cfg(all(feature = "std", unix))] +use std::{ + ffi::CStr, + os::unix::{ + net::{UnixListener, UnixStream}, + {io::AsRawFd, prelude::RawFd}, + }, +}; + +#[cfg(all(feature = "std", unix))] +use libc::{ + c_char, c_int, c_void, malloc, sigaction, sigaltstack, siginfo_t, SA_NODEFER, SA_ONSTACK, + SA_SIGINFO, SIGINT, SIGQUIT, SIGTERM, +}; + +use crate::{ + bolts::shmem::{ShMem, ShMemDescription}, + Error, +}; + +use super::shmem::HasFd; /// We'll start off with 256 megabyte maps per fuzzer client const LLMP_PREF_INITIAL_MAP_SIZE: usize = 1 << 28; @@ -104,6 +132,42 @@ const LLMP_PAGE_HEADER_LEN: usize = size_of::(); /// TAGs used thorughout llmp pub type Tag = u32; +/// Abstraction for listeners +#[cfg(feature = "std")] +pub enum Listener { + Tcp(TcpListener), + Unix(UnixListener), +} + +#[cfg(feature = "std")] +pub enum ListenerStream { + Tcp(TcpStream, std::net::SocketAddr), + Unix(UnixStream, std::os::unix::net::SocketAddr), + Empty(), +} + +#[cfg(feature = "std")] +impl Listener { + fn accept(&self) -> ListenerStream { + match self { + Listener::Tcp(inner) => match inner.accept() { + Ok(res) => ListenerStream::Tcp(res.0, res.1), + Err(err) => { + dbg!("Ignoring failed accept", err); + ListenerStream::Empty() + } + }, + Listener::Unix(inner) => match inner.accept() { + Ok(res) => ListenerStream::Unix(res.0, res.1), + Err(err) => { + dbg!("Ignoring failed accept", err); + ListenerStream::Empty() + } + }, + } + } +} + /// Get sharedmem from a page #[inline] unsafe fn shmem2page_mut(afl_shmem: &mut SH) -> *mut LlmpPage { @@ -324,7 +388,7 @@ where // We got the port. We are the broker! :) dbg!("We're the broker"); let mut broker = LlmpBroker::new()?; - let _listener_thread = broker.launch_tcp_listener(listener)?; + let _listener_thread = broker.launch_listener(Listener::Tcp(listener))?; Ok(LlmpConnection::IsBroker { broker }) } Err(e) => { @@ -368,6 +432,36 @@ where } } +impl LlmpConnection +where + SH: ShMem + HasFd, +{ + #[cfg(all(feature = "std", unix))] + pub fn on_domain_socket(filename: &str) -> Result { + match UnixListener::bind(filename) { + Ok(listener) => { + dbg!("We're the broker"); + let mut broker = LlmpBroker::new()?; + broker.socket_name = Some(filename.to_string()); + let _listener_thread = broker.launch_listener(Listener::Unix(listener))?; + Ok(LlmpConnection::IsBroker { broker }) + } + Err(e) => { + match e.kind() { + std::io::ErrorKind::AddrInUse => { + // We are the client :) + dbg!("We're the client", e); + Ok(LlmpConnection::IsClient { + client: LlmpClient::create_attach_to_unix(filename)?, + }) + } + _ => Err(Error::File(e)), + } + } + } + } +} + /// Contents of the share mem pages, used by llmp internally #[derive(Copy, Clone, Debug)] #[repr(C, packed)] @@ -1140,8 +1234,17 @@ where /// This allows us to intercept messages right in the broker /// This keeps the out map clean. pub llmp_clients: Vec>, + /// This is the socket name, when unix domain sockets are used. + socket_name: Option, + /// This flag is used to indicate that shutdown has been requested by the SIGINT and SIGTERM + /// handlers + shutting_down: bool, } +/// used to access the current broker in signal handler. +#[cfg(all(feature = "std", unix))] +static mut CURRENT_BROKER_PTR: *const c_void = ptr::null(); + /// The broker forwards all messages to its own bus-like broadcast map. /// It may intercept messages passing through. impl LlmpBroker @@ -1160,6 +1263,8 @@ where keep_pages_forever: true, }, llmp_clients: vec![], + socket_name: None, + shutting_down: false, }; Ok(broker) @@ -1219,14 +1324,68 @@ where Ok(()) } + /// Called from an interrupt: Sets broker `shutting_down` flag to `true`. + /// Currently only supported on `std` unix systems. + fn shutdown(&mut self) { + unsafe { ptr::write_volatile(&mut self.shutting_down, true) }; + compiler_fence(Ordering::SeqCst); + } + + #[cfg(all(feature = "std", unix))] + unsafe fn handle_signal(_sig: c_int, _: siginfo_t, _: c_void) { + if !CURRENT_BROKER_PTR.is_null() { + let broker = (CURRENT_BROKER_PTR as *mut LlmpBroker) + .as_mut() + .unwrap(); + broker.shutdown(); + }; + } + + /// For proper cleanup on sigint, we set up a sigint handler + #[cfg(all(feature = "std", unix))] + unsafe fn setup_sigint_handler(&mut self) { + CURRENT_BROKER_PTR = self as *const _ as *const c_void; + + // First, set up our own stack to be used during segfault handling. (and specify `SA_ONSTACK` in `sigaction`) + let signal_stack_size = 2 << 22; + // TODO: We leak the signal stack. Removing the signal handlers, then freeing this mem on teardown would be more correct. + let signal_stack_ptr = malloc(signal_stack_size); + if signal_stack_ptr.is_null() { + panic!( + "Failed to allocate signal stack with {} bytes!", + signal_stack_size + ); + } + sigaltstack(signal_stack_ptr as _, ptr::null_mut() as _); + + let mut sa: sigaction = zeroed(); + libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t); + sa.sa_flags = SA_NODEFER | SA_SIGINFO | SA_ONSTACK; + sa.sa_sigaction = LlmpBroker::::handle_signal as usize; + for (sig, msg) in &[ + (SIGTERM, "segterm"), + (SIGINT, "sigint"), + (SIGQUIT, "sigquit"), + ] { + if sigaction(*sig, &mut sa as *mut sigaction, ptr::null_mut()) < 0 { + panic!("Could not set up {} handler", &msg); + } + } + } + /// Loops infinitely, forwarding and handling all incoming messages from clients. /// Never returns. Panics on error. /// 5 millis of sleep can't hurt to keep busywait not at 100% - pub fn loop_forever(&mut self, on_new_msg: &mut F, sleep_time: Option) -> ! + pub fn loop_forever(&mut self, on_new_msg: &mut F, sleep_time: Option) where F: FnMut(u32, Tag, &[u8]) -> Result, { - loop { + #[cfg(all(feature = "std", unix))] + unsafe { + self.setup_sigint_handler() + }; + + while unsafe { !ptr::read_volatile(&self.shutting_down) } { compiler_fence(Ordering::SeqCst); self.once(on_new_msg) .expect("An error occurred when brokering. Exiting."); @@ -1258,15 +1417,12 @@ where let listener = TcpListener::bind(format!("127.0.0.1:{}", port))?; // accept connections and process them, spawning a new thread for each one println!("Server listening on port {}", port); - self.launch_tcp_listener(listener) + self.launch_listener(Listener::Tcp(listener)) } #[cfg(feature = "std")] - /// Launches a thread using a tcp listener socket, on which new clients may connect to this broker - pub fn launch_tcp_listener( - &mut self, - listener: TcpListener, - ) -> Result, Error> { + /// Launches a thread using a listener socket, on which new clients may connect to this broker + pub fn launch_listener(&mut self, listener: Listener) -> Result, Error> { // Later in the execution, after the initial map filled up, // the current broacast map will will point to a different map. // However, the original map is (as of now) never freed, new clients will start @@ -1298,43 +1454,108 @@ where }; loop { - let (mut stream, addr) = match listener.accept() { - Ok(res) => res, - Err(e) => { - dbg!("Ignoring failed accept", e); - continue; + match listener.accept() { + ListenerStream::Tcp(mut stream, addr) => { + dbg!("New connection", addr, stream.peer_addr().unwrap()); + match stream.write(&broadcast_str_initial) { + Ok(_) => {} // fire & forget + Err(e) => { + dbg!("Could not send to shmap to client", e); + continue; + } + }; + let mut new_client_map_str: [u8; 20] = Default::default(); + match stream.read_exact(&mut new_client_map_str) { + Ok(()) => (), + Err(e) => { + dbg!("Ignoring failed read from client", e); + continue; + } + }; + unsafe { + let msg = new_client_sender + .alloc_next(size_of::()) + .expect("Could not allocate a new message in shared map."); + (*msg).tag = LLMP_TAG_NEW_SHM_CLIENT; + let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; + (*pageinfo).shm_str = new_client_map_str; + (*pageinfo).map_size = LLMP_PREF_INITIAL_MAP_SIZE; + match new_client_sender.send(msg) { + Ok(()) => (), + Err(e) => println!("Error forwarding client on map: {:?}", e), + }; + } } - }; - dbg!("New connection", addr, stream.peer_addr().unwrap()); - match stream.write(&broadcast_str_initial) { - Ok(_) => {} // fire & forget - Err(e) => { - dbg!("Could not send to shmap to client", e); - continue; - } - }; - let mut new_client_map_str: [u8; 20] = Default::default(); - match stream.read_exact(&mut new_client_map_str) { - Ok(()) => (), - Err(e) => { - dbg!("Ignoring failed read from client", e); - continue; - } - }; + ListenerStream::Unix(stream, addr) => unsafe { + dbg!("New connection", addr); - unsafe { - let msg = new_client_sender - .alloc_next(size_of::()) - .expect("Could not allocate a new message in shared map."); - (*msg).tag = LLMP_TAG_NEW_SHM_CLIENT; - let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; - (*pageinfo).shm_str = new_client_map_str; - (*pageinfo).map_size = LLMP_PREF_INITIAL_MAP_SIZE; - match new_client_sender.send(msg) { - Ok(()) => (), - Err(e) => println!("Error forwarding client on map: {:?}", e), - }; - } + let broadcast_fd_initial: i32 = + CStr::from_ptr(broadcast_str_initial.as_ptr() as *const c_char) + .to_string_lossy() + .into_owned() + .parse() + .expect(&format!( + "ShmId is not a valid int file descriptor: {:?}", + broadcast_str_initial + )); + + match sendmsg( + stream.as_raw_fd(), + &[IoVec::from_slice(b"\x00")], + &[ControlMessage::ScmRights(&[broadcast_fd_initial])], + MsgFlags::empty(), + None, + ) { + Ok(_) => {} + Err(err) => { + dbg!("Error sending fd over stream: {}", err); + continue; + } + }; + + let mut buf = [0u8; 5]; + let mut cmsgspace = cmsg_space!([RawFd; 1]); + let msg = recvmsg( + stream.as_raw_fd(), + &[IoVec::from_mut_slice(&mut buf[..])], + Some(&mut cmsgspace), + MsgFlags::empty(), + ) + .unwrap(); + + for cmsg in msg.cmsgs() { + if let ControlMessageOwned::ScmRights(fds) = cmsg { + for fd in fds { + let mut fdstr = [0u8; 20]; + match write!(&mut fdstr[..], "{}", fd) { + Ok(_) => {} + Err(_) => { + dbg!("error converting fd to string"); + } + } + + let msg = new_client_sender + .alloc_next(size_of::()) + .expect("Could not allocate a new message in shared map."); + (*msg).tag = LLMP_TAG_NEW_SHM_CLIENT; + let pageinfo = + (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; + (*pageinfo).shm_str = fdstr; + (*pageinfo).map_size = LLMP_PREF_INITIAL_MAP_SIZE; + match new_client_sender.send(msg) { + Ok(()) => (), + Err(e) => { + println!("Error forwarding client on map: {:?}", e) + } + }; + } + } + } + }, + ListenerStream::Empty() => { + continue; + } + }; } })) } @@ -1417,6 +1638,24 @@ where } } +#[cfg(feature = "std")] +impl Drop for LlmpBroker +where + SH: ShMem, +{ + fn drop(&mut self) { + match &self.socket_name { + Some(name) => match fs::remove_file(&name) { + Ok(_) => {} + Err(err) => { + dbg!("failed to close socket: {}", err); + } + }, + None => {} + } + } +} + /// A restorable client description #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct LlmpClientDescription { @@ -1616,6 +1855,73 @@ where } } +/// `n` clients connect to a broker. They share an outgoing map with the broker, +/// and get incoming messages from the shared broker bus +/// If the Shm has a fd, we can attach to it. +impl LlmpClient +where + SH: ShMem + HasFd, +{ + #[cfg(all(feature = "std", unix))] + /// Create a LlmpClient, getting the ID from a given filename + pub fn create_attach_to_unix(filename: &str) -> Result { + let stream = UnixStream::connect(filename)?; + println!("Connected to socket {}", filename); + + let mut buf = [0u8; 5]; + let mut cmsgspace = cmsg_space!([RawFd; 1]); + let msg = recvmsg( + stream.as_raw_fd(), + &[IoVec::from_mut_slice(&mut buf[..])], + Some(&mut cmsgspace), + MsgFlags::empty(), + ) + .unwrap(); + + for cmsg in msg.cmsgs() { + if let ControlMessageOwned::ScmRights(fds) = cmsg { + for fd in fds { + let mut fdstr = [0u8; 20]; + match write!(&mut fdstr[..], "{}", fd) { + Ok(_) => {} + Err(_) => { + dbg!("error converting fd to string"); + } + } + + let ret = Self::new(LlmpSharedMap::existing(SH::existing_from_shm_slice( + &fdstr, + LLMP_PREF_INITIAL_MAP_SIZE, + )?))?; + + match sendmsg( + stream.as_raw_fd(), + &[IoVec::from_slice(b"\x00")], + &[ControlMessage::ScmRights(&[ret + .sender + .out_maps + .first() + .unwrap() + .shmem + .shm_id()])], + MsgFlags::empty(), + None, + ) { + Ok(_) => {} + Err(err) => { + dbg!("Error sending fd over stream {}", err); + continue; + } + }; + return Ok(ret); + } + } + } + + panic!("Didn't receive a file descriptor from the broker!"); + } +} + #[cfg(test)] mod tests { diff --git a/libafl/src/bolts/shmem.rs b/libafl/src/bolts/shmem.rs index 6313a3dbaa..01bacbefb7 100644 --- a/libafl/src/bolts/shmem.rs +++ b/libafl/src/bolts/shmem.rs @@ -99,17 +99,27 @@ pub trait ShMem: Sized + Debug { } } +/// shared maps that have an id can use this trait +pub trait HasFd { + /// Retrieve the id of this shared map + fn shm_id(&self) -> i32; +} + #[cfg(unix)] #[cfg(feature = "std")] pub mod unix_shmem { use core::{mem::size_of, ptr, slice}; use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_ushort, c_void}; + #[cfg(target_os = "android")] + use libc::{off_t, size_t, MAP_SHARED, O_RDWR, PROT_READ, PROT_WRITE}; use std::ffi::CStr; + #[cfg(target_os = "android")] + use std::ffi::CString; use crate::Error; - use super::ShMem; + use super::{HasFd, ShMem}; #[cfg(unix)] extern "C" { @@ -117,12 +127,119 @@ pub mod unix_shmem { fn snprintf(_: *mut c_char, _: c_ulong, _: *const c_char, _: ...) -> c_int; #[cfg(feature = "std")] fn strncpy(_: *mut c_char, _: *const c_char, _: c_ulong) -> *mut c_char; - #[cfg(feature = "std")] + #[cfg(all(feature = "std", not(target_os = "android")))] fn shmctl(__shmid: c_int, __cmd: c_int, __buf: *mut shmid_ds) -> c_int; - #[cfg(feature = "std")] + #[cfg(all(feature = "std", not(target_os = "android")))] fn shmget(__key: c_int, __size: c_ulong, __shmflg: c_int) -> c_int; - #[cfg(feature = "std")] + #[cfg(all(feature = "std", not(target_os = "android")))] fn shmat(__shmid: c_int, __shmaddr: *const c_void, __shmflg: c_int) -> *mut c_void; + #[cfg(all(feature = "std", target_os = "android"))] + fn ioctl(fd: c_int, request: c_long, ...) -> c_int; + #[cfg(all(feature = "std", target_os = "android"))] + fn open(path: *const c_char, oflag: c_int, ...) -> c_int; + #[cfg(all(feature = "std", target_os = "android"))] + fn close(fd: c_int) -> c_int; + #[cfg(all(feature = "std", target_os = "android"))] + fn mmap( + addr: *mut c_void, + len: size_t, + prot: c_int, + flags: c_int, + fd: c_int, + offset: off_t, + ) -> *mut c_void; + + } + + #[cfg(target_os = "android")] + #[derive(Copy, Clone)] + #[repr(C)] + struct ashmem_pin { + pub offset: c_uint, + pub len: c_uint, + } + + #[cfg(target_os = "android")] + const ASHMEM_GET_SIZE: c_long = 0x00007704; + #[cfg(target_os = "android")] + const ASHMEM_UNPIN: c_long = 0x40087708; + #[cfg(target_os = "android")] + const ASHMEM_SET_NAME: c_long = 0x41007701; + #[cfg(target_os = "android")] + const ASHMEM_SET_SIZE: c_long = 0x40087703; + #[cfg(target_os = "android")] + const ASHMEM_DEVICE: &str = "/dev/ashmem"; + + #[cfg(target_os = "android")] + unsafe fn shmctl(__shmid: c_int, __cmd: c_int, _buf: *mut shmid_ds) -> c_int { + print!("shmctl(__shmid: {})\n", __shmid); + if __cmd == 0 { + let length = ioctl(__shmid, ASHMEM_GET_SIZE); + + let ap = ashmem_pin { + offset: 0, + len: length as u32, + }; + + let ret = ioctl(__shmid, ASHMEM_UNPIN, &ap); + close(__shmid); + ret + } else { + 0 + } + } + + #[cfg(target_os = "android")] + unsafe fn shmget(__key: c_int, __size: c_ulong, __shmflg: c_int) -> c_int { + let path = CString::new(ASHMEM_DEVICE).expect("CString::new failed!"); + let fd = open(path.as_ptr(), O_RDWR); + + let mut ourkey: [c_char; 20] = [0; 20]; + snprintf( + ourkey.as_mut_ptr() as *mut c_char, + size_of::<[c_char; 20]>() as c_ulong, + b"%d\x00" as *const u8 as *const c_char, + __key, + ); + + print!("ourkey: {:?}\n", ourkey); + if ioctl(fd, ASHMEM_SET_NAME, &ourkey) != 0 { + close(fd); + return 0; + }; + + if ioctl(fd, ASHMEM_SET_SIZE, __size) != 0 { + close(fd); + return 0; + }; + + print!("shmget returns {}\n", fd); + fd + } + + #[cfg(target_os = "android")] + unsafe fn shmat(__shmid: c_int, __shmaddr: *const c_void, __shmflg: c_int) -> *mut c_void { + print!("shmat(__shmid: {})\n", __shmid); + + let size = ioctl(__shmid, ASHMEM_GET_SIZE); + if size < 0 { + return 0 as *mut c_void; + } + + let ptr = mmap( + 0 as *mut c_void, + size as usize, + PROT_READ | PROT_WRITE, + MAP_SHARED, + __shmid, + 0, + ); + if ptr == usize::MAX as *mut c_void { + return 0 as *mut c_void; + } + + print!("shmat() = {:?}\n", ptr); + ptr } #[cfg(unix)] @@ -197,6 +314,12 @@ pub mod unix_shmem { } } + impl HasFd for UnixShMem { + fn shm_id(&self) -> i32 { + self.shm_id + } + } + /// Deinit sharedmaps on drop impl Drop for UnixShMem { fn drop(&mut self) { diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index cf8a2ad993..11677cd40a 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -1,4 +1,4 @@ -use crate::bolts::llmp::LlmpSender; +use crate::bolts::{llmp::LlmpSender, shmem::HasFd}; use alloc::{string::ToString, vec::Vec}; use core::{marker::PhantomData, time::Duration}; use serde::{de::DeserializeOwned, Serialize}; @@ -191,6 +191,8 @@ where }, Some(Duration::from_millis(5)), ); + + Ok(()) } _ => Err(Error::IllegalState( "Called broker loop in the client".into(), @@ -298,6 +300,23 @@ where } } +impl LlmpEventManager +where + I: Input, + S: IfInteresting, + SH: ShMem + HasFd, + ST: Stats, +{ + #[cfg(all(feature = "std", unix))] + pub fn new_on_domain_socket(stats: ST, filename: &str) -> Result { + Ok(Self { + stats: Some(stats), + llmp: llmp::LlmpConnection::on_domain_socket(filename)?, + phantom: PhantomData, + }) + } +} + impl EventManager for LlmpEventManager where I: Input, @@ -488,18 +507,28 @@ pub fn setup_restarting_mgr( where I: Input, S: DeserializeOwned + IfInteresting, - SH: ShMem, + SH: ShMem + HasFd, // Todo: HasFd is only needed for Android ST: Stats, { let mut mgr; // We start ourself as child process to actually fuzz if std::env::var(_ENV_FUZZER_SENDER).is_err() { - mgr = LlmpEventManager::::new_on_port(stats, broker_port)?; + let path = std::env::current_dir()?; + mgr = if cfg!(target_os = "android") { + LlmpEventManager::::new_on_domain_socket( + stats, + &format!("{}/.llmp_socket", path.display()).to_string(), + )? + } else { + LlmpEventManager::::new_on_port(stats, broker_port)? + }; + if mgr.is_broker() { // Yep, broker. Just loop here. println!("Doing broker things. Run this tool again to start fuzzing in a client."); mgr.broker_loop()?; + return Err(Error::ShuttingDown); } else { mgr.to_env(_ENV_FUZZER_BROKER_CLIENT_INITIAL); diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 9cd91a940a..e4a17a4d0f 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -215,7 +215,7 @@ pub mod unix_signals { si_addr ); // let's yolo-cat the maps for debugging, if possible. - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "android"))] match fs::read_to_string("/proc/self/maps") { Ok(maps) => println!("maps:\n{}", maps), Err(e) => println!("Couldn't load mappings: {:?}", e), diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index 01fb47a3f9..092a73dfab 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -66,6 +66,8 @@ pub enum Error { IllegalState(String), /// The argument passed to this method or function is not valid IllegalArgument(String), + /// Shutting down, not really an error. + ShuttingDown, /// Something else happened Unknown(String), } @@ -85,6 +87,7 @@ impl fmt::Display for Error { Self::NotImplemented(s) => write!(f, "Not implemented: {0}", &s), Self::IllegalState(s) => write!(f, "Illegal state: {0}", &s), Self::IllegalArgument(s) => write!(f, "Illegal argument: {0}", &s), + Self::ShuttingDown => write!(f, "Shutting down!"), Self::Unknown(s) => write!(f, "Unknown error: {0}", &s), } }