From 1e611da35bf701371a5d8b620450a3501b5984bd Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 19 Dec 2020 05:43:47 +0100 Subject: [PATCH] generic map --- afl/Cargo.toml | 2 +- afl/src/events/llmp.rs | 333 +++++++++++++---------------- afl/src/events/mod.rs | 8 +- afl/src/events/shmem_translated.rs | 278 ------------------------ afl/src/lib.rs | 14 +- fuzzers/libfuzzer/src/lib.rs | 8 +- 6 files changed, 161 insertions(+), 482 deletions(-) delete mode 100644 afl/src/events/shmem_translated.rs diff --git a/afl/Cargo.toml b/afl/Cargo.toml index 21cf033946..7900609236 100644 --- a/afl/Cargo.toml +++ b/afl/Cargo.toml @@ -40,4 +40,4 @@ serde = { version = "1.0", default-features = false, features = ["alloc"] } # se erased-serde = "0.3.12" postcard = { version = "0.5.1", features = ["alloc"] } # no_std compatible serde serialization fromat static_assertions = "1.1.0" -#TODO: for llmp brotli = { version = "3.3.0", default-features = false } # brotli compression +#TODO: for llmp brotli = { version = "3.3.0", default-features = false } # brotli compression \ No newline at end of file diff --git a/afl/src/events/llmp.rs b/afl/src/events/llmp.rs index ec58bcfdf5..8fca736d33 100644 --- a/afl/src/events/llmp.rs +++ b/afl/src/events/llmp.rs @@ -58,7 +58,6 @@ use core::{ #[cfg(feature = "std")] use std::{ - env, io::{Read, Write}, net::{TcpListener, TcpStream}, thread, @@ -68,7 +67,7 @@ use crate::utils::next_pow2; use crate::AflError; #[cfg(feature = "std")] -use super::shmem_translated::{AflShmem, ShMem}; +use super::shmem::ShMem; /// We'll start off with 256 megabyte maps per fuzzer client const LLMP_PREF_INITIAL_MAP_SIZE: usize = 1 << 28; @@ -119,7 +118,7 @@ where #[derive(Clone, Debug)] pub struct LlmpReceiver where - SH: ShMem + SH: ShMem, { pub id: u32, /// Pointer to the last meg this received @@ -150,6 +149,7 @@ where /// shared between one LlmpSender and one LlmpReceiver shmem: SH, } + /// Message sent over the "wire" #[derive(Copy, Clone, Debug)] #[repr(C, packed)] @@ -178,7 +178,7 @@ impl LlmpMsg { /// Gets the buffer from this message as slice, with the corrent length. #[inline] - pub fn as_slice(&self, map: &LlmpSharedMap) -> Result<&[u8], AflError> { + pub fn as_slice(&self, map: &mut LlmpSharedMap) -> Result<&[u8], AflError> { unsafe { if self.in_map(map) { Ok(self.as_slice_unsafe()) @@ -190,7 +190,7 @@ impl LlmpMsg { /// Returns true, if the pointer is, indeed, in the page of this shared map. #[inline] - pub fn in_map(&self, map: &LlmpSharedMap) -> bool { + pub fn in_map(&self, map: &mut LlmpSharedMap) -> bool { unsafe { let map_size = map.shmem.map().len(); let buf_ptr = self.buf.as_ptr(); @@ -209,9 +209,6 @@ impl LlmpMsg { } } - - - /// An Llmp instance pub enum LlmpConnection where @@ -226,7 +223,10 @@ where IsClient { client: LlmpClient }, } -impl LlmpConnection { +impl LlmpConnection +where + SH: ShMem, +{ /// Creates either a broker, if the tcp port is not bound, or a client, connected to this port. pub fn on_port(port: u16) -> Result { match TcpListener::bind(format!("127.0.0.1:{}", port)) { @@ -268,7 +268,7 @@ impl LlmpConnection { } /// Contents of the share mem pages, used by llmp internally -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] #[repr(C, packed)] pub struct LlmpPage { pub sender: u32, @@ -282,7 +282,7 @@ pub struct LlmpPage { } /// The broker (node 0) -#[derive(Clone)] +#[derive(Clone, Debug)] #[repr(C)] pub struct LlmpBroker where @@ -307,7 +307,7 @@ pub enum LlmpMsgHookResult { /// Message payload when a client got added LLMP_TAG_CLIENT_ADDED_V1 */ /// This is an internal message! /// LLMP_TAG_END_OF_PAGE_V1 -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] #[repr(C, packed)] struct LlmpPayloadSharedMapInfo { pub map_size: usize, @@ -316,8 +316,8 @@ struct LlmpPayloadSharedMapInfo { /// Get sharedmem from a page #[inline] -unsafe fn shmem2page(afl_shmem: &SH) -> *mut LlmpPage { - afl_shmem.map().as_mut_ptr() as *mut LlmpPage +unsafe fn shmem2page(afl_shmem: &mut SH) -> *mut LlmpPage { + afl_shmem.map_mut().as_mut_ptr() as *mut LlmpPage } /// Return, if a msg is contained in the current page @@ -357,13 +357,14 @@ fn new_map_size(max_alloc: usize) -> usize { /// Initialize a new llmp_page. size should be relative to /// llmp_page->messages -unsafe fn _llmp_page_init(shmem: &mut AflShmem, sender: u32) { +unsafe fn _llmp_page_init(shmem: &mut SH, sender: u32) { + let map_size = shmem.map().len(); let page = shmem2page(shmem); (*page).sender = sender; ptr::write_volatile(&mut (*page).current_msg_id, 0); (*page).max_alloc_size = 0; // Don't forget to subtract our own header size - (*page).size_total = shmem.map_size - LLMP_PAGE_HEADER_LEN; + (*page).size_total = map_size - LLMP_PAGE_HEADER_LEN; (*page).size_used = 0; (*(*page).messages.as_mut_ptr()).message_id = 0; (*(*page).messages.as_mut_ptr()).tag = LLMP_TAG_UNSET; @@ -373,8 +374,8 @@ unsafe fn _llmp_page_init(shmem: &mut AflShmem, sender: u32) { /// Get the next pointer and make sure it's in the current page, and has enough space. #[inline] -unsafe fn llmp_next_msg_ptr_checked ( - map: &LlmpSharedMap, +unsafe fn llmp_next_msg_ptr_checked( + map: &mut LlmpSharedMap, last_msg: *const LlmpMsg, alloc_size: usize, ) -> Result<*mut LlmpMsg, AflError> { @@ -405,14 +406,17 @@ unsafe fn _llmp_next_msg_ptr(last_msg: *const LlmpMsg) -> *mut LlmpMsg { } /// An actor on the sendin part of the shared map -impl LlmpSender { +impl LlmpSender +where + SH: ShMem, +{ /// For non zero-copy, we want to get rid of old pages with duplicate messages in the client /// eventually. This function This funtion sees if we can unallocate older pages. /// The broker would have informed us by setting the save_to_unmap-flag. unsafe fn prune_old_pages(&mut self) { // Exclude the current page by splitting of the last element for this iter let mut unmap_until_excl = 0; - for map in self.out_maps.split_last().unwrap().1 { + for map in self.out_maps.split_last_mut().unwrap().1 { if (*map.page()).save_to_unmap == 0 { // The broker didn't read this page yet, no more pages to unmap. break; @@ -429,7 +433,7 @@ impl LlmpSender { /// So if alloc_next fails, create new page if necessary, use this function, /// place EOP, commit EOP, reset, alloc again on the new space. unsafe fn alloc_eop(&mut self) -> Result<*mut LlmpMsg, AflError> { - let map = self.out_maps.last().unwrap(); + let mut map = self.out_maps.last_mut().unwrap(); let page = map.page(); let last_msg = self.last_msg_sent; if (*page).size_used + EOP_MSG_SIZE > (*page).size_total { @@ -437,7 +441,7 @@ impl LlmpSender { (*page).size_used, (*page).size_total)); } let mut ret: *mut LlmpMsg = if !last_msg.is_null() { - llmp_next_msg_ptr_checked(&map, last_msg, EOP_MSG_SIZE)? + llmp_next_msg_ptr_checked(&mut map, last_msg, EOP_MSG_SIZE)? } else { (*page).messages.as_mut_ptr() }; @@ -461,7 +465,7 @@ impl LlmpSender { unsafe fn alloc_next_if_space(&mut self, buf_len: usize) -> Option<*mut LlmpMsg> { let buf_len_padded; let mut complete_msg_size = llmp_align(size_of::() + buf_len); - let map = self.out_maps.last().unwrap(); + let map = self.out_maps.last_mut().unwrap(); let page = map.page(); let last_msg = self.last_msg_sent; /* DBG("XXX complete_msg_size %lu (h: %lu)\n", complete_msg_size, sizeof(llmp_message)); */ @@ -554,7 +558,7 @@ impl LlmpSender { (*msg).message_id )); } - let page = self.out_maps.last().unwrap().page(); + let page = self.out_maps.last_mut().unwrap().page(); if msg.is_null() || !llmp_msg_in_page(page, msg) { return Err(AflError::Unknown(format!( "Llmp Message {:?} is null or not in current page", @@ -574,7 +578,10 @@ impl LlmpSender { let old_map = self.out_maps.last_mut().unwrap().page(); // Create a new shard page. - let new_map_shmem = LlmpSharedMap::::new((*old_map).sender, (*old_map).max_alloc_size)?; + let mut new_map_shmem = LlmpSharedMap::new( + (*old_map).sender, + SH::new_map(new_map_size((*old_map).max_alloc_size))?, + ); let mut new_map = new_map_shmem.page(); ptr::write_volatile(&mut (*new_map).current_msg_id, (*old_map).current_msg_id); @@ -626,7 +633,7 @@ impl LlmpSender { pub unsafe fn cancel_send(&mut self, msg: *mut LlmpMsg) { /* DBG("Client %d cancels send of msg at %p with tag 0x%X and size %ld", client->id, msg, msg->tag, * msg->buf_len_padded); */ - let page = self.out_maps.last().unwrap().page(); + let page = self.out_maps.last_mut().unwrap().page(); (*msg).tag = LLMP_TAG_UNSET; (*page).size_used -= (*msg).buf_len_padded as usize + size_of::(); } @@ -682,7 +689,7 @@ where } else { // We don't know how big the msg wants to be, assert at least the header has space. Some(llmp_next_msg_ptr_checked( - &self.current_recv_map, + &mut self.current_recv_map, last_msg, size_of::(), )?) @@ -691,7 +698,7 @@ where // Let's see what we go here. match ret { Some(msg) => { - if !(*msg).in_map(&self.current_recv_map) { + if !(*msg).in_map(&mut self.current_recv_map) { return Err(AflError::IllegalState("Unexpected message in map (out of map bounds) - bugy client or tampered shared map detedted!".into())); } // Handle special, LLMP internal, messages. @@ -717,10 +724,11 @@ where // Mark the old page save to unmap, in case we didn't so earlier. ptr::write_volatile(&mut (*page).save_to_unmap, 1); // Map the new page. The old one should be unmapped by Drop - self.current_recv_map = LlmpSharedMap::new_from_shm_str_buf( - &pageinfo_cpy.shm_str, - pageinfo_cpy.map_size, - )?; + self.current_recv_map = + LlmpSharedMap::existing(SH::existing_map_by_shm_bytes( + &pageinfo_cpy.shm_str, + pageinfo_cpy.map_size, + )?); // Mark the new page save to unmap also (it's mapped by us, the broker now) ptr::write_volatile(&mut (*page).save_to_unmap, 1); @@ -770,7 +778,7 @@ where Some(msg) => Some(( (*msg).sender, (*msg).tag, - (*msg).as_slice(&self.current_recv_map)?, + (*msg).as_slice(&mut self.current_recv_map)?, )), None => None, }) @@ -785,77 +793,53 @@ where Ok(( (*msg).sender, (*msg).tag, - (*msg).as_slice(&self.current_recv_map)?, + (*msg).as_slice(&mut self.current_recv_map)?, )) } } } +// TODO: May be obsolete /// The page struct, placed on a shared mem instance. -impl LlmpSharedMap { - /// Creates a new page with minimum prev_max_alloc_size or LLMP_PREF_INITIAL_MAP_SIZE - /// returning the initialized shared mem struct - pub fn new(sender: u32, min_size: usize) -> Result { - // Create a new shard page. - let mut shmem = AflShmem::new(new_map_size(min_size))?; - unsafe { - _llmp_page_init(&mut shmem, sender); - } - Ok(Self { shmem }) - } - - /// Initialize from a shm_str with fixed len of 20 - pub fn from_name(shm_str: &str, map_size: usize) -> Result { - let slice: [u8; 20]; - slice.copy_from_slice(shm_str.as_bytes()); - Self::from_name_slice(&slice, map_size) - } - - /// Initialize from a shm_str with fixed len of 20 - pub fn from_name_slice(shm_str: &[u8; 20], map_size: usize) -> Result { - let shmem = AflShmem::from_name_slice(shm_str, map_size)?; - // Not initializing the page here - the other side should have done it already! - Ok(Self { shmem }) - } -} - +/// A thin wrapper around a ShMem implementation, with special Llmp funcs impl LlmpSharedMap where SH: ShMem, { - - /// Initialize from a shm_str with fixed len of 20 - pub fn new_from_shm_str_buf(&self, shm_str: &[u8; 20], map_size: usize) -> Result { - let shmem = self.shmem.new_from_shm_str_buf(shm_str, map_size)?; - // Not initializing the page here - the other side should have done it already! - Ok(Self { shmem }) + /// Creates a new page, initializing the passed shared mem struct + pub fn new(sender: u32, mut new_map: SH) -> Self { + unsafe { + _llmp_page_init(&mut new_map, sender); + } + Self { shmem: new_map } } - pub fn write_to_env(&self, env_name: String) -> Result<(), AflError> { - let map_size = self.shmem.map().len(); - let map_env = self.shmem.shm_str() ; - let map_size_env = format!("{}_SIZE", map_env); - env::set_var(map_env, self.shmem.shm_str()); - env::set_var(map_size_env, format!("{}", map_size)); - Ok(()) + /// Maps and wraps an existing + pub fn existing(existing_map: SH) -> Self { + Self { + shmem: existing_map, + } } /// Get the unsafe ptr to this page, situated on the shared map - pub unsafe fn page(&self) -> *mut LlmpPage { - shmem2page(&self.shmem) + pub unsafe fn page(&mut self) -> *mut LlmpPage { + shmem2page(&mut self.shmem) } } /// The broker forwards all messages to its own bus-like broadcast map. /// It may intercept messages passing through. -impl LlmpBroker { +impl LlmpBroker +where + SH: ShMem, +{ /// Create and initialize a new llmp_broker pub fn new() -> Result { let broker = LlmpBroker { llmp_out: LlmpSender { id: 0, last_msg_sent: ptr::null_mut(), - out_maps: vec![LlmpSharedMap::new(0, 0)?], + out_maps: vec![LlmpSharedMap::new(0, SH::new_map(new_map_size(0))?)], // Broker never cleans up the pages so that new // clients may join at any time keep_pages_forever: true, @@ -901,7 +885,6 @@ impl LlmpBroker { Ok(()) } - /// The broker walks all pages and looks for changes, then broadcasts them on /// its own shared page, once. #[inline] @@ -941,11 +924,6 @@ impl LlmpBroker { self.llmp_out.send_buf(tag, buf) } -} - -impl LlmpBroker { - - /// Launches a thread using a tcp listener socket, on which new clients may connect to this broker /// Does so on the given port. pub fn launch_tcp_listener_on( @@ -974,8 +952,11 @@ impl LlmpBroker { let llmp_tcp_id = self.llmp_clients.len() as u32; // Tcp out map sends messages from background thread tcp server to foreground client - let tcp_out_map = LlmpSharedMap::::new(llmp_tcp_id, LLMP_PREF_INITIAL_MAP_SIZE)?; - let tcp_out_map_str = tcp_out_map.shmem.shm_str_buf(); + let tcp_out_map = LlmpSharedMap::new( + llmp_tcp_id, + SH::new_map(new_map_size(LLMP_PREF_INITIAL_MAP_SIZE))?, + ); + let tcp_out_map_str = tcp_out_map.shmem.shm_str(); let tcp_out_map_size = tcp_out_map.shmem.map().len(); self.register_client(tcp_out_map); @@ -983,9 +964,9 @@ impl LlmpBroker { let mut new_client_sender = LlmpSender { id: 0, last_msg_sent: 0 as *mut LlmpMsg, - out_maps: vec![ - LlmpSharedMap::from_name_slice(&tcp_out_map_str, tcp_out_map_size).unwrap(), - ], + out_maps: vec![LlmpSharedMap::existing( + SH::existing_from_name(&tcp_out_map_str, tcp_out_map_size).unwrap(), + )], // drop pages to the broker if it already read them keep_pages_forever: false, }; @@ -1032,26 +1013,91 @@ impl LlmpBroker { })) } - fn map_new_page(shm_str_buf: &[u8; 20], map_size: usize) -> Result, AflError> { - LlmpSharedMap::from_name_slice(shm_str_buf, map_size) + /// broker broadcast to its own page for all others to read */ + #[inline] + unsafe fn handle_new_msgs( + &mut self, + client_id: u32, + on_new_msg: &mut F, + ) -> Result<(), AflError> + where + F: FnMut(u32, Tag, &[u8]) -> Result, + { + let mut next_id = self.llmp_clients.len() as u32; + + // TODO: We could memcpy a range of pending messages, instead of one by one. + loop { + let msg = { + let client = &mut self.llmp_clients[client_id as usize]; + match client.recv()? { + None => { + // We're done handling this client + return Ok(()); + } + Some(msg) => msg, + } + }; + + if (*msg).tag == LLMP_TAG_NEW_SHM_CLIENT { + /* This client informs us about yet another new client + add it to the list! Also, no need to forward this msg. */ + if (*msg).buf_len < size_of::() as u64 { + println!("Ignoring broken CLIENT_ADDED msg due to incorrect size. Expected {} but got {}", + (*msg).buf_len_padded, + size_of::() + ); + } else { + let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; + + match SH::existing_map_by_shm_bytes(&(*pageinfo).shm_str, (*pageinfo).map_size) + { + Ok(new_map) => { + let new_page = LlmpSharedMap::existing(new_map); + let id = next_id; + next_id += 1; + self.llmp_clients.push(LlmpReceiver { + id, + current_recv_map: new_page, + last_msg_recvd: 0 as *mut LlmpMsg, + }); + } + Err(e) => println!("Error adding client! {:?}", e), + }; + } + } else { + // The message is not specifically for use. Let the user handle it, then forward it to the clients, if necessary. + let mut should_forward_msg = true; + + let map = &mut self.llmp_clients[client_id as usize].current_recv_map; + let msg_buf = (*msg).as_slice(map)?; + match (on_new_msg)(client_id, (*msg).tag, msg_buf)? { + LlmpMsgHookResult::Handled => should_forward_msg = false, + _ => (), + } + if should_forward_msg { + self.forward_msg(msg)?; + } + } + } } } /// `n` clients connect to a broker. They share an outgoing map with the broker, /// and get incoming messages from the shared broker bus -impl LlmpClient { - - fn map_new_page(shm_str_buf: &[u8; 20], map_size: usize) -> Result, AflError> { - panic!("End of page not handled!"); - } - +impl LlmpClient +where + SH: ShMem, +{ /// Creates a new LlmpClient pub fn new(initial_broker_map: LlmpSharedMap) -> Result { Ok(Self { llmp_out: LlmpSender { id: 0, last_msg_sent: 0 as *mut LlmpMsg, - out_maps: vec![LlmpSharedMap::new(0, LLMP_PREF_INITIAL_MAP_SIZE)?], + out_maps: vec![LlmpSharedMap::new( + 0, + SH::new_map(new_map_size(LLMP_PREF_INITIAL_MAP_SIZE))?, + )], // drop pages to the broker if it already read them keep_pages_forever: false, }, @@ -1125,86 +1171,9 @@ impl LlmpClient { self.llmp_in.recv_buf_blocking() } - - - /// broker broadcast to its own page for all others to read */ - #[inline] - unsafe fn handle_new_msgs( - &mut self, - client_id: u32, - on_new_msg: &mut F, - ) -> Result<(), AflError> - where - F: FnMut(u32, Tag, &[u8]) -> Result, - { - let mut next_id = self.llmp_clients.len() as u32; - - // TODO: We could memcpy a range of pending messages, instead of one by one. - loop { - let msg = { - let client = &mut self.llmp_clients[client_id as usize]; - match client.recv()? { - None => { - // We're done handling this client - return Ok(()); - } - Some(msg) => msg, - } - }; - - if (*msg).tag == LLMP_TAG_NEW_SHM_CLIENT { - /* This client informs us about yet another new client - add it to the list! Also, no need to forward this msg. */ - if (*msg).buf_len < size_of::() as u64 { - println!("Ignoring broken CLIENT_ADDED msg due to incorrect size. Expected {} but got {}", - (*msg).buf_len_padded, - size_of::() - ); - } else { - let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; - - match LlmpSharedMap::from_name_slice(&(*pageinfo).shm_str, (*pageinfo).map_size) - { - Ok(new_page) => { - let id = next_id; - next_id += 1; - self.llmp_clients.push(LlmpReceiver { - id, - current_recv_map: new_page, - last_msg_recvd: 0 as *mut LlmpMsg, - }); - } - Err(e) => println!("Error adding client! {:?}", e), - }; - } - } else { - // The message is not specifically for use. Let the user handle it, then forward it to the clients, if necessary. - let mut should_forward_msg = true; - - let map = &self.llmp_clients[client_id as usize].current_recv_map; - let msg_buf = (*msg).as_slice(map)?; - match (on_new_msg)(client_id, (*msg).tag, msg_buf)? { - LlmpMsgHookResult::Handled => should_forward_msg = false, - _ => (), - } - if should_forward_msg { - self.forward_msg(msg)?; - } - } - } - } - -} - -impl LlmpClient { - /// Creates a new LlmpClient, reading the map id and len from env pub fn create_using_env(env_var: &str) -> Result { - - let map_str = env::var(env_var)?; - let map_size = str::parse::(&env::var(format!("{}_SIZE", env_var))?)?; - Ok(Self::new(LlmpSharedMap::from_name(&map_str, map_size)?)?) - + Self::new(LlmpSharedMap::existing(SH::existing_from_env(env_var)?)) } /// Create a LlmpClient, getting the ID from a given port @@ -1215,15 +1184,14 @@ impl LlmpClient { let mut new_broker_map_str: [u8; 20] = Default::default(); stream.read_exact(&mut new_broker_map_str)?; - let ret = Self::new(LlmpSharedMap::from_name_slice( + let ret = Self::new(LlmpSharedMap::existing(SH::existing_map_by_shm_bytes( &new_broker_map_str, LLMP_PREF_INITIAL_MAP_SIZE, - )?)?; + )?))?; stream.write(ret.llmp_out.out_maps.first().unwrap().shmem.shm_str_buf())?; Ok(ret) } - } #[cfg(test)] @@ -1231,6 +1199,8 @@ mod tests { use std::{thread::sleep, time::Duration}; + use crate::events::shmem::AflShmem; + use super::{ LlmpConnection::{self, IsBroker, IsClient}, LlmpMsgHookResult::ForwardToClients, @@ -1239,7 +1209,7 @@ mod tests { #[test] pub fn llmp_connection() { - let mut broker = match LlmpConnection::on_port(1337).unwrap() { + let mut broker = match LlmpConnection::::on_port(1337).unwrap() { IsClient { client: _ } => panic!("Could not bind to port as broker"), IsBroker { broker, @@ -1248,7 +1218,7 @@ mod tests { }; // Add the first client (2nd, actually, because of the tcp listener client) - let mut client = match LlmpConnection::on_port(1337).unwrap() { + let mut client = match LlmpConnection::::on_port(1337).unwrap() { IsBroker { broker: _, listener_thread: _, @@ -1277,5 +1247,4 @@ mod tests { // We want at least the tcp and sender clients. assert_eq!(broker.llmp_clients.len(), 2); } - } diff --git a/afl/src/events/mod.rs b/afl/src/events/mod.rs index 9c2355a4fe..de2059a94b 100644 --- a/afl/src/events/mod.rs +++ b/afl/src/events/mod.rs @@ -1,19 +1,17 @@ -// TODO: llmp can be no_std, if we abstract away page creation -#[cfg(feature = "std")] pub mod llmp; #[cfg(feature = "std")] -pub mod shmem_translated; +pub mod shmem; use alloc::string::{String, ToString}; use alloc::vec::Vec; -use shmem_translated::AflShmem; use core::time::Duration; use core::{marker::PhantomData, time}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -#[cfg(feature = "std")] use self::llmp::Tag; +#[cfg(feature = "std")] +use self::shmem::AflShmem; use crate::corpus::Corpus; use crate::executors::Executor; use crate::feedbacks::FeedbacksTuple; diff --git a/afl/src/events/shmem_translated.rs b/afl/src/events/shmem_translated.rs deleted file mode 100644 index e4857dd054..0000000000 --- a/afl/src/events/shmem_translated.rs +++ /dev/null @@ -1,278 +0,0 @@ -use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_ushort, c_void}; -use core::slice; -use std::{ffi::CStr, mem::size_of}; - -use crate::AflError; - -extern "C" { - fn snprintf(_: *mut c_char, _: c_ulong, _: *const c_char, _: ...) -> c_int; - fn strncpy(_: *mut c_char, _: *const c_char, _: c_ulong) -> *mut c_char; - //fn strlen(_: *const c_char) -> c_ulong; - fn shmctl(__shmid: c_int, __cmd: c_int, __buf: *mut shmid_ds) -> c_int; - fn shmget(__key: c_int, __size: c_ulong, __shmflg: c_int) -> c_int; - fn shmat(__shmid: c_int, __shmaddr: *const c_void, __shmflg: c_int) -> *mut c_void; - //fn strtol(_: *const c_char, _: *mut *mut c_char, _: c_int) -> c_long; - fn setenv(__name: *const c_char, __value: *const c_char, __replace: c_int) -> c_int; -} -#[derive(Copy, Clone)] -#[repr(C)] -struct ipc_perm { - pub __key: c_int, - pub uid: c_uint, - pub gid: c_uint, - pub cuid: c_uint, - pub cgid: c_uint, - pub mode: c_ushort, - pub __pad1: c_ushort, - pub __seq: c_ushort, - pub __pad2: c_ushort, - pub __glibc_reserved1: c_ulong, - pub __glibc_reserved2: c_ulong, -} - -#[derive(Copy, Clone)] -#[repr(C)] -struct shmid_ds { - pub shm_perm: ipc_perm, - pub shm_segsz: c_ulong, - pub shm_atime: c_long, - pub shm_dtime: c_long, - pub shm_ctime: c_long, - pub shm_cpid: c_int, - pub shm_lpid: c_int, - pub shm_nattch: c_ulong, - pub __glibc_reserved4: c_ulong, - pub __glibc_reserved5: c_ulong, -} -const AFL_RET_ERRNO: c_uint = 12; -const AFL_RET_NULL_PTR: c_uint = 11; -const AFL_RET_SUCCESS: c_uint = 0; - -// A generic sharememory region to be used by any functions (queues or feedbacks -// too.) - -/// A Shared map -pub trait ShMem { - - /// The string to identify this shm - fn shm_str(&self) -> String; - - /// Let's just fix this to a large enough buf - fn shm_str_buf(&self) -> &[u8; 20]; - - /// The actual shared map, in memory - fn map(&self) -> &[u8]; - - /// The actual shared map, mutable - fn map_mut(&mut self) -> &mut [u8]; - -} - -#[derive(Clone, Debug)] -pub struct AflShmem { - pub shm_str: [u8; 20], - pub shm_id: c_int, - pub map: *mut u8, - pub map_size: usize, -} - -impl ShMem for AflShmem { - - fn shm_str(&self) -> String { - unsafe { CStr::from_ptr(self.shm_str.as_ptr() as *const i8) }.to_string_lossy().into() - } - - fn shm_str_buf(&self) -> &[u8; 20] { - &self.shm_str - } - - 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) } - } - -} - -/// Deinit sharedmaps on drop -impl Drop for AflShmem { - fn drop(&mut self) { - unsafe { - afl_shmem_deinit(self); - } - } -} - -/// Create an uninitialized shmap -const fn afl_shmem_unitialized() -> AflShmem { - AflShmem { - shm_str: [0; 20], - shm_id: -1, - map: 0 as *mut c_uchar, - map_size: 0, - } -} - -impl AflShmem { - pub fn from_str(shm_str: &CStr, map_size: usize) -> Result { - let mut ret = afl_shmem_unitialized(); - let map = unsafe { afl_shmem_by_str(&mut ret, shm_str, map_size) }; - if map != 0 as *mut u8 { - Ok(ret) - } else { - Err(AflError::Unknown(format!( - "Could not allocate map with id {:?} and size {}", - shm_str, map_size - ))) - } - } - - /// Generate a shared map with a fixed byte array of 20 - pub fn from_name_slice(shm_str: &[u8; 20], map_size: usize) -> Result { - unsafe { - let str_bytes = shm_str as *const [u8; 20] as *const libc::c_char; - Self::from_str(CStr::from_ptr(str_bytes), map_size) - } - } - - pub fn new(map_size: usize) -> Result { - let mut ret = afl_shmem_unitialized(); - let map = unsafe { afl_shmem_init(&mut ret, map_size) }; - if map != 0 as *mut u8 { - Ok(ret) - } else { - Err(AflError::Unknown(format!( - "Could not allocate map of size {}", - map_size - ))) - } - } - - /// Sets this shm id as env variable with the given name - /// Also write the map size as name#_SIZE env - pub fn to_env_var(&self, env_name: &CStr) -> Result<(), AflError> { - if unsafe { afl_shmem_to_env_var(&self, env_name) } == AFL_RET_SUCCESS { - Ok(()) - } else { - Err(AflError::Unknown(format!( - "Could not set env variable {:?}", - env_name - ))) - } - } -} - -/// Deinitialize this shmem instance -unsafe fn afl_shmem_deinit(shm: *mut AflShmem) { - if shm.is_null() || (*shm).map.is_null() { - /* Serialized map id */ - // Not set or not initialized; - return; - } - (*shm).shm_str[0 as usize] = '\u{0}' as u8; - shmctl((*shm).shm_id, 0 as c_int, 0 as *mut shmid_ds); - (*shm).map = 0 as *mut c_uchar; -} - -/// Functions to create Shared memory region, for observation channels and -/// opening inputs and stuff. -unsafe fn afl_shmem_init(shm: *mut AflShmem, map_size: usize) -> *mut c_uchar { - (*shm).map_size = map_size; - (*shm).map = 0 as *mut c_uchar; - (*shm).shm_id = shmget( - 0 as c_int, - map_size as c_ulong, - 0o1000 as c_int | 0o2000 as c_int | 0o600 as c_int, - ); - if (*shm).shm_id < 0 as c_int { - (*shm).shm_str[0] = '\u{0}' as u8; - return 0 as *mut c_uchar; - } - snprintf( - (*shm).shm_str.as_mut_ptr() as *mut i8, - size_of::<[c_char; 20]>() as c_ulong, - b"%d\x00" as *const u8 as *const c_char, - (*shm).shm_id, - ); - (*shm).shm_str - [(size_of::<[c_char; 20]>() as c_ulong).wrapping_sub(1 as c_int as c_ulong) as usize] = - '\u{0}' as u8; - (*shm).map = shmat((*shm).shm_id, 0 as *const c_void, 0 as c_int) as *mut c_uchar; - if (*shm).map == -(1 as c_int) as *mut c_void as *mut c_uchar || (*shm).map.is_null() { - shmctl((*shm).shm_id, 0 as c_int, 0 as *mut shmid_ds); - (*shm).shm_id = -(1 as c_int); - (*shm).shm_str[0 as c_int as usize] = '\u{0}' as u8; - return 0 as *mut c_uchar; - } - return (*shm).map; -} - -/// Uses a shmap id string to open a shared map -unsafe fn afl_shmem_by_str(shm: *mut AflShmem, shm_str: &CStr, map_size: usize) -> *mut c_uchar { - if shm.is_null() || shm_str.to_bytes().len() == 0 || map_size == 0 { - return 0 as *mut c_uchar; - } - (*shm).map = 0 as *mut c_uchar; - (*shm).map_size = map_size; - strncpy( - (*shm).shm_str.as_mut_ptr() as *mut c_char, - shm_str.as_ptr() as *const c_char, - (size_of::<[c_char; 20]>() as c_ulong).wrapping_sub(1 as c_int as c_ulong), - ); - (*shm).shm_id = shm_str - .to_str() - .expect(&format!("illegal shm_str {:?}", shm_str)) - .parse::() - .unwrap(); - (*shm).map = shmat((*shm).shm_id, 0 as *const c_void, 0 as c_int) as *mut c_uchar; - if (*shm).map == -(1 as c_int) as *mut c_void as *mut c_uchar { - (*shm).map = 0 as *mut c_uchar; - (*shm).map_size = 0; - (*shm).shm_str[0] = '\u{0}' as u8; - return 0 as *mut c_uchar; - } - return (*shm).map; -} - -/// Write sharedmap as env var and the size as name#_SIZE -unsafe fn afl_shmem_to_env_var(shmem: &AflShmem, env_name: &CStr) -> c_uint { - let env_len = env_name.to_bytes().len(); - if env_len == 0 || env_len > 200 || (*shmem).shm_str[0 as c_int as usize] == 0 { - return AFL_RET_NULL_PTR; - } - let mut shm_str: [c_char; 256] = [0; 256]; - snprintf( - shm_str.as_mut_ptr(), - size_of::<[c_char; 256]>() as c_ulong, - b"%d\x00" as *const u8 as *const c_char, - (*shmem).shm_id, - ); - if setenv( - env_name.as_ptr() as *const c_char, - shm_str.as_mut_ptr(), - 1 as c_int, - ) < 0 as c_int - { - return AFL_RET_ERRNO; - } - /* Write the size to env, too */ - let mut size_env_name: [c_char; 256] = [0; 256]; - snprintf( - size_env_name.as_mut_ptr(), - size_of::<[c_char; 256]>() as c_ulong, - b"%s_SIZE\x00" as *const u8 as *const c_char, - env_name, - ); - snprintf( - shm_str.as_mut_ptr(), - size_of::<[c_char; 256]>() as c_ulong, - b"%d\x00" as *const u8 as *const c_char, - (*shmem).shm_id, - ); - if setenv(size_env_name.as_mut_ptr(), shm_str.as_mut_ptr(), 1 as c_int) < 0 as c_int { - return AFL_RET_ERRNO; - } - return AFL_RET_SUCCESS; -} diff --git a/afl/src/lib.rs b/afl/src/lib.rs index 042f1f7f2c..dfdc76cccd 100644 --- a/afl/src/lib.rs +++ b/afl/src/lib.rs @@ -6,7 +6,6 @@ Welcome to libAFL #[macro_use] extern crate alloc; - #[macro_use] extern crate static_assertions; @@ -94,25 +93,16 @@ impl From for AflError { Self::Unknown(format!("Could not convert byte to utf-8: {:?}", err)) } } - + #[cfg(feature = "std")] impl From for AflError { fn from(err: VarError) -> Self { Self::Empty(format!("Could not get env var: {:?}", err)) } } - + impl From for AflError { fn from(err: ParseIntError) -> Self { Self::Unknown(format!("Failed to parse Int: {:?}", err)) } } - - -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/fuzzers/libfuzzer/src/lib.rs b/fuzzers/libfuzzer/src/lib.rs index 8715db2a59..f9e2cbca62 100644 --- a/fuzzers/libfuzzer/src/lib.rs +++ b/fuzzers/libfuzzer/src/lib.rs @@ -46,10 +46,10 @@ pub extern "C" fn afl_libfuzzer_main() { let stats = SimpleStats::new(|s| println!("{}", s)); - /// - match LlmpFuzzInstance::from_env("FUZZER_ENV") { - - } + // TODO + /* match LlmpFuzzInstance::from_env("FUZZER_ENV") { + + }*/ let mut mgr = LlmpEventManager::new_on_port(1337, stats).unwrap(); if mgr.is_broker() {