From 392ffd33f7ce8d706138f625b357cc7fc042b2ee Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 7 Jun 2021 01:48:52 +0200 Subject: [PATCH 1/8] Fix client_id for outgoing messages (#154) * attaching client_id to outgoing messages * fixed forwarding, example --- libafl/examples/llmp_test/main.rs | 5 +++-- libafl/src/bolts/llmp.rs | 32 ++++++++++++++++++------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/libafl/examples/llmp_test/main.rs b/libafl/examples/llmp_test/main.rs index 0324dace4f..43a73ea375 100644 --- a/libafl/examples/llmp_test/main.rs +++ b/libafl/examples/llmp_test/main.rs @@ -31,7 +31,7 @@ fn adder_loop(port: u16) -> ! { loop { let mut msg_counter = 0; loop { - let (_sender, tag, buf) = match client.recv_buf().unwrap() { + let (sender, tag, buf) = match client.recv_buf().unwrap() { None => break, Some(msg) => msg, }; @@ -42,8 +42,9 @@ fn adder_loop(port: u16) -> ! { current_result.wrapping_add(u32::from_le_bytes(buf.try_into().unwrap())); } _ => println!( - "Adder Client ignored unknown message {} with {} bytes", + "Adder Client ignored unknown message {:#x} from client {} with {} bytes", tag, + sender, buf.len() ), }; diff --git a/libafl/src/bolts/llmp.rs b/libafl/src/bolts/llmp.rs index 5a5f1ce0ed..981c860b76 100644 --- a/libafl/src/bolts/llmp.rs +++ b/libafl/src/bolts/llmp.rs @@ -697,7 +697,7 @@ pub struct LlmpSender where SP: ShMemProvider, { - /// ID of this sender. Only used in the broker. + /// ID of this sender. pub id: u32, /// Ref to the last message this sender sent on the last page. /// If null, a new page (just) started. @@ -967,8 +967,9 @@ where /// Commit the message last allocated by [`alloc_next`] to the queue. /// After commiting, the msg shall no longer be altered! /// It will be read by the consuming threads (`broker->clients` or `client->broker`) + /// If `overwrite_client_id` is `false`, the message's `sender` won't be touched (for broker forwarding) #[inline(never)] // Not inlined to make cpu-level reodering (hopefully?) improbable - unsafe fn send(&mut self, msg: *mut LlmpMsg) -> Result<(), Error> { + unsafe fn send(&mut self, msg: *mut LlmpMsg, overwrite_client_id: bool) -> Result<(), Error> { // dbg!("Sending msg {:?}", msg); if self.last_msg_sent == msg { @@ -977,6 +978,10 @@ where if (*msg).tag == LLMP_TAG_UNSET { panic!("No tag set on message with id {}", (*msg).message_id); } + // A client gets the sender id assigned to by the broker during the initial handshake. + if overwrite_client_id { + (*msg).sender = self.id; + } let page = self.out_maps.last_mut().unwrap().page_mut(); if msg.is_null() || !llmp_msg_in_page(page, msg) { return Err(Error::Unknown(format!( @@ -1034,17 +1039,18 @@ where println!("Setting max alloc size: {:?}", (*old_map).max_alloc_size); (*new_map).max_alloc_size = (*old_map).max_alloc_size; + (*new_map).sender = self.id; + /* On the old map, place a last message linking to the new map for the clients * to consume */ - let mut out: *mut LlmpMsg = self.alloc_eop()?; - (*out).sender = (*old_map).sender; + let out = self.alloc_eop()?; let mut end_of_page_msg = (*out).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; (*end_of_page_msg).map_size = new_map_shmem.shmem.len(); (*end_of_page_msg).shm_str = *new_map_shmem.shmem.id().as_slice(); /* Send the last msg on the old buf */ - self.send(out)?; + self.send(out, true)?; // Set the new page as current page. self.out_maps.push(new_map_shmem); @@ -1115,7 +1121,7 @@ where (*msg).flags = LLMP_FLAG_INITIALIZED; buf.as_ptr() .copy_to_nonoverlapping((*msg).buf.as_mut_ptr(), buf.len()); - self.send(msg) + self.send(msg, true) } } @@ -1139,7 +1145,7 @@ where (*msg).flags = flags; buf.as_ptr() .copy_to_nonoverlapping((*msg).buf.as_mut_ptr(), buf.len()); - self.send(msg) + self.send(msg, true) } } @@ -1355,7 +1361,7 @@ where /// Returns the next message, tag, buf, if avaliable, else None #[allow(clippy::type_complexity)] #[inline] - pub fn recv_buf(&mut self) -> Result, Error> { + pub fn recv_buf(&mut self) -> Result, Error> { if let Some((sender, tag, _flags, buf)) = self.recv_buf_with_flags()? { Ok(Some((sender, tag, buf))) } else { @@ -1744,7 +1750,7 @@ where (msg as *const u8).copy_to_nonoverlapping(out as *mut u8, complete_size); (*out).buf_len_padded = actual_size; /* We need to replace the message ID with our own */ - if let Err(e) = self.llmp_out.send(out) { + if let Err(e) = self.llmp_out.send(out, false) { panic!("Error sending msg: {:?}", e) }; self.llmp_out.last_msg_sent = out; @@ -1855,7 +1861,7 @@ where let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; (*pageinfo).shm_str = *shmem_description.id.as_slice(); (*pageinfo).map_size = shmem_description.size; - sender.send(msg) + sender.send(msg, true) } } @@ -2377,7 +2383,7 @@ where /// # Safety /// Needs to be called with a proper msg pointer pub unsafe fn send(&mut self, msg: *mut LlmpMsg) -> Result<(), Error> { - self.sender.send(msg) + self.sender.send(msg, true) } /// Allocates a message of the given size, tags it, and sends it off. @@ -2439,13 +2445,13 @@ where /// Returns the next message, tag, buf, if avaliable, else None #[allow(clippy::type_complexity)] #[inline] - pub fn recv_buf(&mut self) -> Result, Error> { + pub fn recv_buf(&mut self) -> Result, Error> { self.receiver.recv_buf() } /// Receives a buf from the broker, looping until a messages becomes avaliable #[inline] - pub fn recv_buf_blocking(&mut self) -> Result<(u32, Tag, &[u8]), Error> { + pub fn recv_buf_blocking(&mut self) -> Result<(ClientId, Tag, &[u8]), Error> { self.receiver.recv_buf_blocking() } From 35e655ca04a524bf679dcdeb1d2f8813287d40ab Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 7 Jun 2021 02:15:31 +0200 Subject: [PATCH 2/8] LLMP Changes (#130) * llmp_changes * fixed send * no_std fixes --- libafl/src/bolts/llmp.rs | 177 ++++++++++++++++++++------------------ libafl/src/events/llmp.rs | 4 +- 2 files changed, 97 insertions(+), 84 deletions(-) diff --git a/libafl/src/bolts/llmp.rs b/libafl/src/bolts/llmp.rs index 981c860b76..9bc26c45dd 100644 --- a/libafl/src/bolts/llmp.rs +++ b/libafl/src/bolts/llmp.rs @@ -62,7 +62,7 @@ For broker2broker communication, all messages are forwarded via network sockets. use alloc::{string::String, vec::Vec}; use core::{ cmp::max, - convert::TryFrom, + convert::{TryFrom, TryInto}, fmt::Debug, mem::size_of, ptr, slice, @@ -73,7 +73,6 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] use std::{ - convert::TryInto, env, io::{ErrorKind, Read, Write}, net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs}, @@ -709,6 +708,9 @@ where /// By keeping the message history around, /// new clients may join at any time in the future. pub keep_pages_forever: bool, + /// True, if we allocatd a message, but didn't call [`Self::send()`] yet + has_unsent_message: bool, + /// The sharedmem provider to get new sharaed maps if we're full shmem_provider: SP, } @@ -730,6 +732,7 @@ where )], // drop pages to the broker if it already read them keep_pages_forever, + has_unsent_message: false, shmem_provider, }) } @@ -804,6 +807,7 @@ where out_maps: vec![out_map], // drop pages to the broker if it already read them keep_pages_forever: false, + has_unsent_message: false, shmem_provider, }) } @@ -864,103 +868,76 @@ where /// Never call [`alloc_next`] without either sending or cancelling the last allocated message for this page! /// There can only ever be up to one message allocated per page at each given time. 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_mut().unwrap(); let page = map.page_mut(); let last_msg = self.last_msg_sent; + + if self.has_unsent_message { + panic!("Called alloc without callind send inbetween"); + } + #[cfg(all(feature = "llmp_debug", feature = "std"))] println!( - "Allocating {} (>={}) bytes on page {:?} / map {:?} (last msg: {:?})", - complete_msg_size, buf_len, page, &map, last_msg + "Allocating {} bytes on page {:?} / map {:?} (last msg: {:?})", + buf_len, page, &map, last_msg ); - /* DBG("XXX complete_msg_size %lu (h: %lu)\n", complete_msg_size, sizeof(llmp_message)); */ - /* In case we don't have enough space, make sure the next page will be large - * enough */ - // For future allocs, keep track of the maximum (aligned) alloc size we used - (*page).max_alloc_size = max((*page).max_alloc_size, complete_msg_size); - let mut ret: *mut LlmpMsg; - /* DBG("last_msg %p %d (%d)\n", last_msg, last_msg ? (int)last_msg->tag : -1, (int)LLMP_TAG_END_OF_PAGE_V1); */ - if last_msg.is_null() || (*last_msg).tag == LLMP_TAG_END_OF_PAGE { - /* We start fresh, on a new page */ - ret = (*page).messages.as_mut_ptr(); - /* The initial message may not be alligned, so we at least align the end of - it. Technically, c_ulong can be smaller than a pointer, then who knows what - happens */ - let base_addr = ret as usize; - buf_len_padded = - llmp_align(base_addr + complete_msg_size) - base_addr - size_of::(); - complete_msg_size = buf_len_padded + size_of::(); - /* Still space for the new message plus the additional "we're full" message? - */ + let msg_start = (*page).messages.as_mut_ptr() as usize + (*page).size_used; + // Make sure the end of our msg is aligned. + let buf_len_padded = llmp_align(msg_start + buf_len + size_of::()) + - msg_start + - size_of::(); + + #[cfg(all(feature = "llmp_debug", feature = "std"))] + dbg!( + page, + *page, + (*page).size_used, + buf_len_padded, + EOP_MSG_SIZE, + (*page).size_total + ); + + // We need enough space for the current page size_used + payload + padding + if (*page).size_used + size_of::() + buf_len_padded + EOP_MSG_SIZE + > (*page).size_total + { #[cfg(all(feature = "llmp_debug", feature = "std"))] - dbg!( - page, - *page, - (*page).size_used, - complete_msg_size, - EOP_MSG_SIZE, - (*page).size_total - ); - if (*page).size_used + complete_msg_size + EOP_MSG_SIZE > (*page).size_total { - /* We're full. */ - return None; - } - /* We need to start with 1 for ids, as current message id is initialized - * with 0... */ - (*ret).message_id = if last_msg.is_null() { - 1 - } else { - (*last_msg).message_id + 1 - } - } else if (*page).current_msg_id == (*last_msg).message_id { - buf_len_padded = complete_msg_size - size_of::(); - /* DBG("XXX ret %p id %u buf_len_padded %lu complete_msg_size %lu\n", ret, ret->message_id, buf_len_padded, - * complete_msg_size); */ + println!("LLMP: Page full."); - /* Still space for the new message plus the additional "we're full" message? */ - if (*page).size_used + complete_msg_size + EOP_MSG_SIZE > (*page).size_total { - /* We're full. */ - return None; - } - ret = match llmp_next_msg_ptr_checked(map, last_msg, complete_msg_size) { - Ok(msg) => msg, - Err(e) => { - #[cfg(feature = "std")] - dbg!("Unexpected error allocing new msg", e); - #[cfg(feature = "std")] - return None; - #[cfg(not(feature = "std"))] - panic!("Unexpected error allocing new msg {:?}", e); - } - }; - (*ret).message_id = (*last_msg).message_id + 1 + /* We're full. */ + return None; + } + + let ret = msg_start as *mut LlmpMsg; + + /* We need to start with 1 for ids, as current message id is initialized + * with 0... */ + (*ret).message_id = if last_msg.is_null() { + 1 + } else if (*page).current_msg_id == (*last_msg).message_id { + (*last_msg).message_id + 1 } else { /* Oops, wrong usage! */ panic!("BUG: The current message never got committed using send! (page->current_msg_id {:?}, last_msg->message_id: {})", ptr::addr_of!((*page).current_msg_id), (*last_msg).message_id); - } + }; - /* The beginning of our message should be messages + size_used, else nobody - * sent the last msg! */ - /* DBG("XXX ret %p - page->messages %p = %lu != %lu, will add %lu -> %p\n", ret, page->messages, - (c_ulong)((u8 *)ret - (u8 *)page->messages), page->size_used, complete_msg_size, ((u8 *)ret) + complete_msg_size); - */ - - if last_msg.is_null() && (*page).size_used != 0 - || ((ret as usize) - (*page).messages.as_mut_ptr() as usize) != (*page).size_used - { - panic!("Allocated new message without calling send() inbetween. ret: {:?}, page: {:?}, complete_msg_size: {:?}, size_used: {:?}, last_msg: {:?}", ret, page, - buf_len_padded, ptr::addr_of!((*page).size_used), last_msg); - } - (*page).size_used += complete_msg_size; - (*ret).buf_len_padded = buf_len_padded as u64; (*ret).buf_len = buf_len as u64; - /* DBG("Returning new message at %p with len %ld, TAG was %x", ret, ret->buf_len_padded, ret->tag); */ - /* Maybe catch some bugs... */ + (*ret).buf_len_padded = buf_len_padded as u64; + (*page).size_used += size_of::() + buf_len_padded; + (*_llmp_next_msg_ptr(ret)).tag = LLMP_TAG_UNSET; (*ret).tag = LLMP_TAG_UNINITIALIZED; + + // For future allocs, keep track of the maximum (aligned) alloc size we used + (*page).max_alloc_size = max( + (*page).max_alloc_size, + size_of::() + buf_len_padded, + ); + + self.has_unsent_message = true; + Some(ret) } @@ -994,6 +971,7 @@ where ptr::write_volatile(ptr::addr_of_mut!((*page).current_msg_id), (*msg).message_id); compiler_fence(Ordering::SeqCst); self.last_msg_sent = msg; + self.has_unsent_message = false; Ok(()) } @@ -1101,6 +1079,38 @@ where (*page).size_used -= (*msg).buf_len_padded as usize + size_of::(); } + /// Shrinks the allocated [`LlmpMsg`] to a given size. + pub unsafe fn shrink_alloced( + &mut self, + msg: *mut LlmpMsg, + shrinked_len: usize, + ) -> Result<(), Error> { + let old_len_padded = (*msg).buf_len_padded; + + let msg_start = msg as usize; + // Make sure the end of our msg is aligned. + let buf_len_padded = llmp_align(msg_start + shrinked_len + size_of::()) + - msg_start + - size_of::(); + + if buf_len_padded > old_len_padded.try_into().unwrap() { + return Err(Error::IllegalArgument(format!("Cannot shrink msg of size {} (paded: {}) to requested larger size of {} (padded: {})!", (*msg).buf_len, old_len_padded, shrinked_len, buf_len_padded))); + } + + (*msg).buf_len = shrinked_len as u64; + (*msg).buf_len_padded = buf_len_padded as u64; + + let page = self.out_maps.last_mut().unwrap().page_mut(); + + // Doing this step by step will catch underflows in debug builds :) + (*page).size_used -= old_len_padded as usize; + (*page).size_used += buf_len_padded as usize; + + (*_llmp_next_msg_ptr(msg)).tag = LLMP_TAG_UNSET; + + Ok(()) + } + /// Allocates a message of the given size, tags it, and sends it off. pub fn send_buf(&mut self, tag: Tag, buf: &[u8]) -> Result<(), Error> { // Make sure we don't reuse already allocated tags @@ -1633,6 +1643,7 @@ where // Broker never cleans up the pages so that new // clients may join at any time keep_pages_forever: true, + has_unsent_message: false, shmem_provider: shmem_provider.clone(), }, llmp_clients: vec![], @@ -2099,6 +2110,7 @@ where )], // drop pages to the broker, if it already read them. keep_pages_forever: false, + has_unsent_message: false, shmem_provider: shmem_provider_clone.clone(), }; @@ -2366,6 +2378,7 @@ where })], // drop pages to the broker if it already read them keep_pages_forever: false, + has_unsent_message: false, shmem_provider: shmem_provider.clone(), }, diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index bb5530c821..44fe2d7351 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -10,7 +10,7 @@ use core::ptr::{addr_of, read_volatile}; #[cfg(feature = "std")] use crate::bolts::{ - llmp::{LlmpClient, LlmpReceiver}, + llmp::{LlmpClient, LlmpConnection, LlmpReceiver}, shmem::StdShMemProvider, }; @@ -19,7 +19,7 @@ use std::net::{SocketAddr, ToSocketAddrs}; use crate::{ bolts::{ - llmp::{self, Flags, LlmpClientDescription, LlmpConnection, LlmpSender, Tag}, + llmp::{self, Flags, LlmpClientDescription, LlmpSender, Tag}, shmem::ShMemProvider, }, events::{BrokerEventResult, Event, EventFirer, EventManager, EventProcessor, EventRestarter}, From 36b823548a2293bfa840b1f26f6cf0942644f2de Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 7 Jun 2021 12:30:56 +0200 Subject: [PATCH 3/8] nightly clippy fixes (#155) * nightly clippy fixes * more niglty clippy fixes * added Safety section * no_std fixes * final fixes --- fuzzers/frida_libpng/src/fuzzer.rs | 2 +- libafl/src/bolts/compress.rs | 4 +- libafl/src/bolts/launcher.rs | 2 +- libafl/src/bolts/llmp.rs | 57 ++++++++++++++++++++-------- libafl/src/bolts/os/ashmem_server.rs | 6 +-- libafl/src/bolts/rands.rs | 2 +- libafl/src/bolts/shmem.rs | 4 +- libafl/src/events/llmp.rs | 24 +++++++----- libafl/src/executors/forkserver.rs | 4 +- libafl/src/executors/inprocess.rs | 13 +++---- libafl/src/feedbacks/mod.rs | 23 +++++------ libafl/src/fuzzer.rs | 4 +- libafl/src/mutators/mutations.rs | 12 ++++-- libafl/src/mutators/scheduled.rs | 4 +- libafl/src/observers/cmp.rs | 2 +- libafl/src/observers/map.rs | 6 +-- libafl/src/state/mod.rs | 2 +- libafl/src/stats/mod.rs | 4 +- libafl_frida/src/asan_errors.rs | 5 ++- libafl_frida/src/asan_rt.rs | 24 ++++++------ libafl_frida/src/helper.rs | 8 ++-- libafl_targets/src/libfuzzer.rs | 4 +- 22 files changed, 125 insertions(+), 91 deletions(-) diff --git a/fuzzers/frida_libpng/src/fuzzer.rs b/fuzzers/frida_libpng/src/fuzzer.rs index 721cded413..76a5954d6e 100644 --- a/fuzzers/frida_libpng/src/fuzzer.rs +++ b/fuzzers/frida_libpng/src/fuzzer.rs @@ -273,7 +273,7 @@ fn fuzz( /// The actual fuzzer #[cfg(unix)] -#[allow(clippy::too_many_lines, clippy::clippy::too_many_arguments)] +#[allow(clippy::too_many_lines, clippy::too_many_arguments)] unsafe fn fuzz( module_name: &str, symbol_name: &str, diff --git a/libafl/src/bolts/compress.rs b/libafl/src/bolts/compress.rs index a5a7b313f6..58d0bd0c45 100644 --- a/libafl/src/bolts/compress.rs +++ b/libafl/src/bolts/compress.rs @@ -32,7 +32,7 @@ impl GzipCompressor { //compress if the buffer is large enough let compressed = buf .iter() - .cloned() + .copied() .encode(&mut GZipEncoder::new(), Action::Finish) .collect::, _>>()?; Ok(Some(compressed)) @@ -47,7 +47,7 @@ impl GzipCompressor { pub fn decompress(&self, buf: &[u8]) -> Result, Error> { Ok(buf .iter() - .cloned() + .copied() .decode(&mut GZipDecoder::new()) .collect::, _>>()?) } diff --git a/libafl/src/bolts/launcher.rs b/libafl/src/bolts/launcher.rs index 4ffe92933b..113c7d77b1 100644 --- a/libafl/src/bolts/launcher.rs +++ b/libafl/src/bolts/launcher.rs @@ -236,4 +236,4 @@ where } } -const _AFL_LAUNCHER_CLIENT: &str = &"AFL_LAUNCHER_CLIENT"; +const _AFL_LAUNCHER_CLIENT: &str = "AFL_LAUNCHER_CLIENT"; diff --git a/libafl/src/bolts/llmp.rs b/libafl/src/bolts/llmp.rs index 9bc26c45dd..20584e7290 100644 --- a/libafl/src/bolts/llmp.rs +++ b/libafl/src/bolts/llmp.rs @@ -280,12 +280,14 @@ impl Listener { /// Get sharedmem from a page #[inline] +#[allow(clippy::cast_ptr_alignment)] unsafe fn shmem2page_mut(afl_shmem: &mut SHM) -> *mut LlmpPage { afl_shmem.map_mut().as_mut_ptr() as *mut LlmpPage } /// Get sharedmem from a page #[inline] +#[allow(clippy::cast_ptr_alignment)] unsafe fn shmem2page(afl_shmem: &SHM) -> *const LlmpPage { afl_shmem.map().as_ptr() as *const LlmpPage } @@ -459,7 +461,9 @@ unsafe fn llmp_next_msg_ptr_checked( } /// Pointer to the message behind the last message +/// The messages are padded, so accesses will be aligned properly. #[inline] +#[allow(clippy::cast_ptr_alignment)] unsafe fn _llmp_next_msg_ptr(last_msg: *const LlmpMsg) -> *mut LlmpMsg { /* DBG("_llmp_next_msg_ptr %p %lu + %lu\n", last_msg, last_msg->buf_len_padded, sizeof(llmp_message)); */ (last_msg as *mut u8) @@ -488,7 +492,7 @@ pub enum LlmpMsgHookResult { /// Message sent over the "wire" #[derive(Copy, Clone, Debug)] -#[repr(C, packed)] +#[repr(C)] pub struct LlmpMsg { /// A tag pub tag: Tag, //u32 @@ -620,7 +624,7 @@ where pub fn describe(&self) -> Result { Ok(match self { LlmpConnection::IsClient { client } => client.describe()?, - _ => todo!("Only client can be described atm."), + LlmpConnection::IsBroker { .. } => todo!("Only client can be described atm."), }) } @@ -653,7 +657,7 @@ where /// Contents of the share mem pages, used by llmp internally #[derive(Copy, Clone, Debug)] -#[repr(C, packed)] +#[repr(C)] pub struct LlmpPage { /// to check if this page got initialized properly pub magic: u64, @@ -682,7 +686,7 @@ pub struct LlmpPage { /// This is an internal message! /// [`LLMP_TAG_END_OF_PAGE_V1`] #[derive(Copy, Clone, Debug)] -#[repr(C, packed)] +#[repr(C)] struct LlmpPayloadSharedMapInfo { /// The map size pub map_size: usize, @@ -1023,6 +1027,7 @@ where * to consume */ let out = self.alloc_eop()?; + #[allow(clippy::cast_ptr_alignment)] let mut end_of_page_msg = (*out).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; (*end_of_page_msg).map_size = new_map_shmem.shmem.len(); (*end_of_page_msg).shm_str = *new_map_shmem.shmem.id().as_slice(); @@ -1080,11 +1085,24 @@ where } /// Shrinks the allocated [`LlmpMsg`] to a given size. + /// + /// # Safety + /// The msg pointer will be dereferenced, if it's not `null`. pub unsafe fn shrink_alloced( &mut self, msg: *mut LlmpMsg, shrinked_len: usize, ) -> Result<(), Error> { + if msg.is_null() { + return Err(Error::IllegalArgument( + "Null msg passed to shrink_alloced".into(), + )); + } else if !self.has_unsent_message { + return Err(Error::IllegalState( + "Called shrink_alloced, but the msg was not unsent".into(), + )); + } + let old_len_padded = (*msg).buf_len_padded; let msg_start = msg as usize; @@ -1303,6 +1321,7 @@ where size_of::() ); } + #[allow(clippy::cast_ptr_alignment)] let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; /* The pageinfo points to the map we're about to unmap. @@ -1355,7 +1374,7 @@ where if (*last_msg).tag == LLMP_TAG_END_OF_PAGE && !llmp_msg_in_page(page, last_msg) { panic!("BUG: full page passed to await_message_blocking or reset failed"); } - current_msg_id = (*last_msg).message_id + current_msg_id = (*last_msg).message_id; } loop { compiler_fence(Ordering::SeqCst); @@ -1557,18 +1576,19 @@ where #[cfg(feature = "std")] pub unsafe fn msg_to_env(&self, msg: *const LlmpMsg, map_env_name: &str) -> Result<(), Error> { if msg.is_null() { - env::set_var(&format!("{}_OFFSET", map_env_name), _NULL_ENV_STR) + env::set_var(&format!("{}_OFFSET", map_env_name), _NULL_ENV_STR); } else { env::set_var( &format!("{}_OFFSET", map_env_name), format!("{}", self.msg_to_offset(msg)?), - ) - }; + ); + } Ok(()) } /// Gets this message from this page, at the indicated offset. /// Will return [`crate::Error::IllegalArgument`] error if the offset is out of bounds. + #[allow(clippy::cast_ptr_alignment)] pub fn msg_from_offset(&mut self, offset: u64) -> Result<*mut LlmpMsg, Error> { let offset = offset as usize; unsafe { @@ -1616,7 +1636,9 @@ pub struct LlmpBrokerSignalHandler { #[cfg(unix)] impl Handler for LlmpBrokerSignalHandler { fn handle(&mut self, _signal: Signal, _info: siginfo_t, _context: &mut ucontext_t) { - unsafe { ptr::write_volatile(&mut self.shutting_down, true) }; + unsafe { + ptr::write_volatile(&mut self.shutting_down, true); + } } fn signals(&self) -> Vec { @@ -1762,8 +1784,8 @@ where (*out).buf_len_padded = actual_size; /* We need to replace the message ID with our own */ if let Err(e) = self.llmp_out.send(out, false) { - panic!("Error sending msg: {:?}", e) - }; + panic!("Error sending msg: {:?}", e); + } self.llmp_out.last_msg_sent = out; Ok(()) } @@ -1820,8 +1842,8 @@ where #[cfg(feature = "std")] if let Some(time) = sleep_time { - thread::sleep(time) - }; + thread::sleep(time); + } #[cfg(not(feature = "std"))] match sleep_time { @@ -1869,6 +1891,7 @@ where .alloc_next(size_of::()) .expect("Could not allocate a new message in shared map."); (*msg).tag = LLMP_TAG_NEW_SHM_CLIENT; + #[allow(clippy::cast_ptr_alignment)] let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; (*pageinfo).shm_str = *shmem_description.id.as_slice(); (*pageinfo).map_size = shmem_description.size; @@ -2051,7 +2074,7 @@ where stream, shmem_provider, *current_client_id, - &broker_map_description, + broker_map_description, ) { if Self::announce_new_client(sender, &shmem_description).is_err() { println!("B2B: Error announcing client {:?}", shmem_description); @@ -2166,6 +2189,7 @@ where /// broker broadcast to its own page for all others to read */ #[inline] + #[allow(clippy::cast_ptr_alignment)] unsafe fn handle_new_msgs(&mut self, client_id: u32, on_new_msg: &mut F) -> Result<(), Error> where F: FnMut(ClientId, Tag, Flags, &[u8]) -> Result, @@ -2239,8 +2263,8 @@ where if let LlmpMsgHookResult::Handled = (on_new_msg)(client_id, (*msg).tag, (*msg).flags, msg_buf)? { - should_forward_msg = false - }; + should_forward_msg = false; + } if should_forward_msg { self.forward_msg(msg)?; } @@ -2421,6 +2445,7 @@ where .alloc_next(size_of::()) .expect("Could not allocate a new message in shared map."); (*msg).tag = LLMP_TAG_NEW_SHM_CLIENT; + #[allow(clippy::cast_ptr_alignment)] let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; (*pageinfo).shm_str = *shm_str; (*pageinfo).map_size = shm_id; diff --git a/libafl/src/bolts/os/ashmem_server.rs b/libafl/src/bolts/os/ashmem_server.rs index e3a68b0968..ff23a9bd64 100644 --- a/libafl/src/bolts/os/ashmem_server.rs +++ b/libafl/src/bolts/os/ashmem_server.rs @@ -329,18 +329,18 @@ impl AshmemService { let client = self.clients.get_mut(&client_id).unwrap(); client .stream - .send_fds(&id.to_string().as_bytes(), &[server_fd])?; + .send_fds(id.to_string().as_bytes(), &[server_fd])?; client.maps.entry(server_fd).or_default().push(mapping); } AshmemResponse::Id(id) => { let client = self.clients.get_mut(&client_id).unwrap(); - client.stream.send_fds(&id.to_string().as_bytes(), &[])?; + client.stream.send_fds(id.to_string().as_bytes(), &[])?; } AshmemResponse::RefCount(refcount) => { let client = self.clients.get_mut(&client_id).unwrap(); client .stream - .send_fds(&refcount.to_string().as_bytes(), &[])?; + .send_fds(refcount.to_string().as_bytes(), &[])?; } } Ok(()) diff --git a/libafl/src/bolts/rands.rs b/libafl/src/bolts/rands.rs index b53794f494..32869d8d97 100644 --- a/libafl/src/bolts/rands.rs +++ b/libafl/src/bolts/rands.rs @@ -327,7 +327,7 @@ pub struct XkcdRand { #[cfg(test)] impl Rand for XkcdRand { fn set_seed(&mut self, val: u64) { - self.val = val + self.val = val; } fn next(&mut self) -> u64 { diff --git a/libafl/src/bolts/shmem.rs b/libafl/src/bolts/shmem.rs index bbd7db0d07..cc352722cd 100644 --- a/libafl/src/bolts/shmem.rs +++ b/libafl/src/bolts/shmem.rs @@ -248,7 +248,7 @@ where impl Drop for RcShMem { fn drop(&mut self) { - self.provider.borrow_mut().release_map(&mut self.internal) + self.provider.borrow_mut().release_map(&mut self.internal); } } @@ -303,7 +303,7 @@ where } fn release_map(&mut self, map: &mut Self::Mem) { - self.internal.borrow_mut().release_map(&mut map.internal) + self.internal.borrow_mut().release_map(&mut map.internal); } fn clone_ref(&mut self, mapping: &Self::Mem) -> Result { diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index 44fe2d7351..9f6cf73164 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -263,7 +263,7 @@ where { /// LLMP clients will have to wait until their pages are mapped by somebody. fn drop(&mut self) { - self.await_restart_safe() + self.await_restart_safe(); } } @@ -332,7 +332,7 @@ where /// Write the config for a client [`EventManager`] to env vars, a new client can reattach using [`LlmpEventManager::existing_client_from_env()`]. #[cfg(feature = "std")] pub fn to_env(&self, env_name: &str) { - self.llmp.to_env(env_name).unwrap() + self.llmp.to_env(env_name).unwrap(); } // Handle arriving events in the client @@ -510,7 +510,7 @@ where S: DeserializeOwned, SP: ShMemProvider, { - let tuple: (S, _) = postcard::from_bytes(&state_corpus_serialized)?; + let tuple: (S, _) = postcard::from_bytes(state_corpus_serialized)?; Ok(( tuple.0, LlmpEventManager::existing_client_from_description(shmem_provider, &tuple.1)?, @@ -558,13 +558,15 @@ where /// Otherwise, the OS may already have removed the shared maps, #[inline] fn await_restart_safe(&mut self) { - self.llmp_mgr.await_restart_safe() + self.llmp_mgr.await_restart_safe(); } /// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner. fn on_restart(&mut self, state: &mut S) -> Result<(), Error> { // First, reset the page to 0 so the next iteration can read read from the beginning of this page - unsafe { self.sender.reset() }; + unsafe { + self.sender.reset(); + } let state_corpus_serialized = serialize_state_mgr(state, &self.llmp_mgr)?; self.sender .send_buf(_LLMP_TAG_RESTART, &state_corpus_serialized) @@ -598,10 +600,10 @@ where } /// The llmp connection from the actual fuzzer to the process supervising it -const _ENV_FUZZER_SENDER: &str = &"_AFL_ENV_FUZZER_SENDER"; -const _ENV_FUZZER_RECEIVER: &str = &"_AFL_ENV_FUZZER_RECEIVER"; +const _ENV_FUZZER_SENDER: &str = "_AFL_ENV_FUZZER_SENDER"; +const _ENV_FUZZER_RECEIVER: &str = "_AFL_ENV_FUZZER_RECEIVER"; /// The llmp (2 way) connection from a fuzzer to the broker (broadcasting all other fuzzer messages) -const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = &"_AFL_ENV_FUZZER_BROKER_CLIENT"; +const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT"; impl LlmpRestartingEventManager where @@ -881,13 +883,15 @@ where Some((_sender, _tag, msg)) => { println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len()); let (state, mgr): (S, LlmpEventManager) = - deserialize_state_mgr(new_shmem_provider, &msg)?; + deserialize_state_mgr(new_shmem_provider, msg)?; (Some(state), LlmpRestartingEventManager::new(mgr, sender)) } }; // We reset the sender, the next sender and receiver (after crash) will reuse the page from the initial message. - unsafe { mgr.sender_mut().reset() }; + unsafe { + mgr.sender_mut().reset(); + } /* TODO: Not sure if this is needed // We commit an empty NO_RESTART message to this buf, against infinite loops, // in case something crashes in the fuzzer. diff --git a/libafl/src/executors/forkserver.rs b/libafl/src/executors/forkserver.rs index 1cb34d4dca..719300710b 100644 --- a/libafl/src/executors/forkserver.rs +++ b/libafl/src/executors/forkserver.rs @@ -346,7 +346,7 @@ where self.executor .out_file_mut() - .write_buf(&input.target_bytes().as_slice()); + .write_buf(input.target_bytes().as_slice()); let send_len = self .executor @@ -505,7 +505,7 @@ where let mut exit_kind = ExitKind::Ok; // Write to testcase - self.out_file.write_buf(&input.target_bytes().as_slice()); + self.out_file.write_buf(input.target_bytes().as_slice()); let send_len = self .forkserver diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 441d9cc6fe..a3a05fbfdc 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -208,7 +208,7 @@ where /// Retrieve the harness function. #[inline] pub fn harness(&self) -> &H { - &self.harness_fn + self.harness_fn } /// Retrieve the harness function for a mutable reference. @@ -286,7 +286,7 @@ mod unix_signal_handler { let data = &mut GLOBAL_STATE; match signal { Signal::SigUser2 | Signal::SigAlarm => { - (data.timeout_handler)(signal, info, context, data) + (data.timeout_handler)(signal, info, context, data); } _ => (data.crash_handler)(signal, info, context, data), } @@ -342,7 +342,7 @@ mod unix_signal_handler { let interesting = fuzzer .objective_mut() - .is_interesting(state, event_mgr, &input, observers, &ExitKind::Timeout) + .is_interesting(state, event_mgr, input, observers, &ExitKind::Timeout) .expect("In timeout handler objective failure."); if interesting { @@ -433,7 +433,6 @@ mod unix_signal_handler { } // TODO tell the parent to not restart - libc::_exit(1); } else { let state = (data.state_ptr as *mut S).as_mut().unwrap(); let event_mgr = (data.event_mgr_ptr as *mut EM).as_mut().unwrap(); @@ -481,7 +480,7 @@ mod unix_signal_handler { let interesting = fuzzer .objective_mut() - .is_interesting(state, event_mgr, &input, observers, &ExitKind::Crash) + .is_interesting(state, event_mgr, input, observers, &ExitKind::Crash) .expect("In crash handler objective failure."); if interesting { @@ -512,9 +511,9 @@ mod unix_signal_handler { event_mgr.await_restart_safe(); #[cfg(feature = "std")] println!("Bye!"); - - libc::_exit(1); } + + libc::_exit(1); } } diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index 2103a894cb..0f725d4976 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -62,7 +62,7 @@ where let start_time = crate::cpu::read_time_counter(); // Execute this feedback - let ret = self.is_interesting(state, manager, input, observers, &exit_kind); + let ret = self.is_interesting(state, manager, input, observers, exit_kind); // Get the elapsed time for checking this feedback let elapsed = crate::cpu::read_time_counter() - start_time; @@ -244,6 +244,7 @@ where OT: ObserversTuple; #[cfg(feature = "introspection")] + #[allow(clippy::too_many_arguments)] fn is_pair_interesting_with_perf( first: &mut A, second: &mut B, @@ -315,7 +316,7 @@ where manager, input, observers, - &exit_kind, + exit_kind, feedback_stats, feedback_index, )?; @@ -325,7 +326,7 @@ where manager, input, observers, - &exit_kind, + exit_kind, feedback_stats, feedback_index + 1, )?; @@ -386,7 +387,7 @@ where manager, input, observers, - &exit_kind, + exit_kind, feedback_stats, feedback_index, )?; @@ -400,7 +401,7 @@ where manager, input, observers, - &exit_kind, + exit_kind, feedback_stats, feedback_index + 1, ) @@ -457,7 +458,7 @@ where manager, input, observers, - &exit_kind, + exit_kind, feedback_stats, feedback_index, )?; @@ -467,7 +468,7 @@ where manager, input, observers, - &exit_kind, + exit_kind, feedback_stats, feedback_index + 1, )?; @@ -499,7 +500,7 @@ where OT: ObserversTuple, { let a = first.is_interesting(state, manager, input, observers, exit_kind)?; - if a == false { + if !a { return Ok(false); } @@ -528,12 +529,12 @@ where manager, input, observers, - &exit_kind, + exit_kind, feedback_stats, feedback_index, )?; - if a == false { + if !a { return Ok(false); } @@ -542,7 +543,7 @@ where manager, input, observers, - &exit_kind, + exit_kind, feedback_stats, feedback_index + 1, ) diff --git a/libafl/src/fuzzer.rs b/libafl/src/fuzzer.rs index 45a01d6f89..a24b3fb924 100644 --- a/libafl/src/fuzzer.rs +++ b/libafl/src/fuzzer.rs @@ -541,7 +541,7 @@ where start_timer!(state); let is_solution = self .objective_mut() - .is_interesting(state, event_mgr, &input, observers, &exit_kind)?; + .is_interesting(state, event_mgr, input, observers, &exit_kind)?; mark_feature_time!(state, PerfFeature::GetObjectivesInterestingAll); if is_solution { @@ -564,7 +564,7 @@ where let is_interesting = self.feedback_mut().is_interesting_with_perf( state, event_mgr, - &input, + input, observers, &exit_kind, &mut feedback_stats, diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index 8c4ae524c1..fc21659765 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -25,7 +25,9 @@ pub fn buffer_self_copy(data: &mut [u8], from: usize, to: usize, len: usize) { debug_assert!(to + len <= data.len()); if len != 0 && from != to { let ptr = data.as_mut_ptr(); - unsafe { core::ptr::copy(ptr.add(from), ptr.add(to), len) } + unsafe { + core::ptr::copy(ptr.add(from), ptr.add(to), len); + } } } @@ -39,7 +41,9 @@ pub fn buffer_copy(dst: &mut [u8], src: &[u8], from: usize, to: usize, len: usiz let dst_ptr = dst.as_mut_ptr(); let src_ptr = src.as_ptr(); if len != 0 { - unsafe { core::ptr::copy(src_ptr.add(from), dst_ptr.add(to), len) } + unsafe { + core::ptr::copy(src_ptr.add(from), dst_ptr.add(to), len); + } } } @@ -50,7 +54,7 @@ pub fn buffer_copy(dst: &mut [u8], src: &[u8], from: usize, to: usize, len: usiz fn buffer_set(data: &mut [u8], from: usize, len: usize, val: u8) { debug_assert!(from + len <= data.len()); for p in &mut data[from..(from + len)] { - *p = val + *p = val; } } @@ -1406,7 +1410,7 @@ where let other = other_testcase.load_input()?; input .bytes_mut() - .splice(split_at.., other.bytes()[split_at..].iter().cloned()); + .splice(split_at.., other.bytes()[split_at..].iter().copied()); Ok(MutationResult::Mutated) } diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index 1691e32179..85fba5e87c 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -338,7 +338,7 @@ where let mut log = Vec::::new(); while let Some(idx) = self.mutation_log.pop() { let name = String::from(self.scheduled.mutations().name(idx).unwrap()); // TODO maybe return an Error on None - log.push(name) + log.push(name); } let meta = LogMutationMetadata::new(log); testcase.add_metadata(meta); @@ -471,7 +471,7 @@ mod tests { // The pre-seeded rand should have spliced at position 2. // TODO: Maybe have a fixed rand for this purpose? - assert_eq!(input.bytes(), &[b'a', b'b', b'f']) + assert_eq!(input.bytes(), &[b'a', b'b', b'f']); } #[test] diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index 29fa3b79d3..015487ab06 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -39,7 +39,7 @@ impl CmpValues { CmpValues::U16(t) => Some((u64::from(t.0), u64::from(t.1))), CmpValues::U32(t) => Some((u64::from(t.0), u64::from(t.1))), CmpValues::U64(t) => Some(*t), - _ => None, + CmpValues::Bytes(_) => None, } } } diff --git a/libafl/src/observers/map.rs b/libafl/src/observers/map.rs index 39632199d3..622f9321a1 100644 --- a/libafl/src/observers/map.rs +++ b/libafl/src/observers/map.rs @@ -128,7 +128,7 @@ where #[inline] fn set_initial(&mut self, initial: T) { - self.initial = initial + self.initial = initial; } } @@ -249,7 +249,7 @@ where #[inline] fn set_initial(&mut self, initial: T) { - self.initial = initial + self.initial = initial; } } @@ -371,7 +371,7 @@ where #[inline] fn set_initial(&mut self, initial: T) { - self.initial = initial + self.initial = initial; } } diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 5b4c204296..4b7d791df5 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -320,7 +320,7 @@ where } fn set_max_size(&mut self, max_size: usize) { - self.max_size = max_size + self.max_size = max_size; } } diff --git a/libafl/src/stats/mod.rs b/libafl/src/stats/mod.rs index fc4814a3c7..f5ef8f4445 100644 --- a/libafl/src/stats/mod.rs +++ b/libafl/src/stats/mod.rs @@ -190,7 +190,7 @@ pub trait Stats { self.client_stats_mut().push(ClientStats { last_window_time: current_time(), ..ClientStats::default() - }) + }); } &mut self.client_stats_mut()[client_id as usize] } @@ -512,7 +512,7 @@ impl ClientPerfStats { let elapsed = self.mark_time(); // Add the time to the scheduler stat - self.update_scheduler(elapsed) + self.update_scheduler(elapsed); } /// Update the time spent in the scheduler with the elapsed time that we have seen diff --git a/libafl_frida/src/asan_errors.rs b/libafl_frida/src/asan_errors.rs index 5d962d291e..3b04f5eb44 100644 --- a/libafl_frida/src/asan_errors.rs +++ b/libafl_frida/src/asan_errors.rs @@ -86,7 +86,7 @@ impl AsanErrors { /// Clears this `AsanErrors` struct pub fn clear(&mut self) { - self.errors.clear() + self.errors.clear(); } /// Gets the amount of `AsanErrors` in this struct @@ -102,6 +102,7 @@ impl AsanErrors { } /// Get a mutable reference to the global [`AsanErrors`] object + #[must_use] pub fn get_mut<'a>() -> &'a mut Self { unsafe { ASAN_ERRORS.as_mut().unwrap() } } @@ -121,7 +122,7 @@ impl AsanErrors { .add_frame_filter(Box::new(|frames| { frames.retain( |x| matches!(&x.name, Some(n) if !n.starts_with("libafl_frida::asan_rt::")), - ) + ); })); #[allow(clippy::non_ascii_literal)] diff --git a/libafl_frida/src/asan_rt.rs b/libafl_frida/src/asan_rt.rs index 94e6c74736..20f7682701 100644 --- a/libafl_frida/src/asan_rt.rs +++ b/libafl_frida/src/asan_rt.rs @@ -148,7 +148,7 @@ impl AsanRuntime { /// Check if the test leaked any memory and report it if so. pub fn check_for_leaks(&mut self) { - self.allocator.check_for_leaks() + self.allocator.check_for_leaks(); } /// Returns the `AsanErrors` from the recent run @@ -174,17 +174,15 @@ impl AsanRuntime { /// real address, the stalked address is returned. #[must_use] pub fn real_address_for_stalked(&self, stalked: usize) -> usize { - if let Some(addr) = self.stalked_addresses.get(&stalked) { - *addr - } else { - stalked - } + self.stalked_addresses + .get(&stalked) + .map_or(stalked, |addr| *addr) } /// Unpoison all the memory that is currently mapped with read/write permissions. #[allow(clippy::unused_self)] fn unpoison_all_existing_memory(&mut self) { - self.allocator.unpoison_all_existing_memory() + self.allocator.unpoison_all_existing_memory(); } /// Register the current thread with the runtime, implementing shadow memory for its stack and @@ -240,7 +238,9 @@ impl AsanRuntime { let stack_address = &mut stack_var as *mut _ as *mut c_void as usize; let range_details = RangeDetails::with_address(stack_address as u64).unwrap(); // Write something to (hopefully) make sure the val isn't optimized out - unsafe { write_volatile(&mut stack_var, 0xfadbeef) }; + unsafe { + write_volatile(&mut stack_var, 0xfadbeef); + } let start = range_details.memory_range().base_address().0 as usize; let end = start + range_details.memory_range().size(); @@ -1873,7 +1873,7 @@ impl AsanRuntime { actual_pc = insn.address() as usize; } - let detail = cs.insn_detail(&insn).unwrap(); + let detail = cs.insn_detail(insn).unwrap(); let arch_detail = detail.arch_detail(); let (mut base_reg, mut index_reg, displacement) = if let Arm64Operand(arm64operand) = arch_detail.operands().last().unwrap() { @@ -1910,12 +1910,12 @@ impl AsanRuntime { base_reg -= capstone::arch::arm64::Arm64Reg::ARM64_REG_S0 as u16; } - #[allow(clippy::clippy::cast_possible_wrap)] + #[allow(clippy::cast_possible_wrap)] let mut fault_address = (self.regs[base_reg as usize] as isize + displacement as isize) as usize; if index_reg == 0 { - index_reg = 0xffff + index_reg = 0xffff; } else { if capstone::arch::arm64::Arm64Reg::ARM64_REG_X0 as u16 <= index_reg && index_reg <= capstone::arch::arm64::Arm64Reg::ARM64_REG_X28 as u16 @@ -1998,7 +1998,7 @@ impl AsanRuntime { AsanErrors::get_mut().report_error(error); } - #[allow(clippy::unused_self)] + #[allow(clippy::unused_self, clippy::identity_op)] // identity_op appears to be a false positive in ubfx fn generate_shadow_check_function(&mut self) { let shadow_bit = self.allocator.shadow_bit(); let mut ops = dynasmrt::VecAssembler::::new(0); diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index 9645dd16bf..d2bbafba1b 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -218,7 +218,7 @@ fn pc(context: &CpuContext) -> usize { /// The implementation of the [`FridaInstrumentationHelper`] impl<'a> FridaInstrumentationHelper<'a> { /// Constructor function to create a new [`FridaInstrumentationHelper`], given a `module_name`. - #[allow(clippy::clippy::too_many_lines)] + #[allow(clippy::too_many_lines)] #[must_use] pub fn new( gum: &'a Gum, @@ -318,7 +318,7 @@ impl<'a> FridaInstrumentationHelper<'a> { helper .drcov_basic_blocks .push(DrCovBasicBlock::new(real_address, real_address + 4)); - }) + }); } } @@ -348,7 +348,7 @@ impl<'a> FridaInstrumentationHelper<'a> { ); } } - instruction.keep() + instruction.keep(); } }); helper.transformer = Some(transformer); @@ -361,7 +361,7 @@ impl<'a> FridaInstrumentationHelper<'a> { #[inline] fn options(&self) -> &FridaOptions { - &self.options + self.options } #[cfg(target_arch = "aarch64")] #[inline] diff --git a/libafl_targets/src/libfuzzer.rs b/libafl_targets/src/libfuzzer.rs index 0e72a690ee..4effe6c140 100644 --- a/libafl_targets/src/libfuzzer.rs +++ b/libafl_targets/src/libfuzzer.rs @@ -15,7 +15,7 @@ extern "C" { /// # Safety /// Calls the libfuzzer-style init function which is native code. #[allow(clippy::similar_names)] -#[allow(clippy::clippy::must_use_candidate)] // nobody uses that return code... +#[allow(clippy::must_use_candidate)] // nobody uses that return code... pub fn libfuzzer_initialize(args: &[String]) -> i32 { let argv: Vec<*const u8> = args.iter().map(|x| x.as_bytes().as_ptr()).collect(); assert!(argv.len() < i32::MAX as usize); @@ -32,7 +32,7 @@ pub fn libfuzzer_initialize(args: &[String]) -> i32 { /// Call a single input of a libfuzzer-style cpp-harness /// # Safety /// Calls the libfuzzer harness. We actually think the target is unsafe and crashes eventually, that's why we do all this fuzzing. -#[allow(clippy::clippy::must_use_candidate)] +#[allow(clippy::must_use_candidate)] pub fn libfuzzer_test_one_input(buf: &[u8]) -> i32 { unsafe { LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len()) } } From 397a43c5d3a24d6deea89bd360c26ba6c47a45c3 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 8 Jun 2021 09:53:58 +0200 Subject: [PATCH 4/8] update build.rs for libafl_targets --- libafl_targets/build.rs | 10 +++++-- libafl_targets/src/sancov_cmp.c | 52 ++++++++++----------------------- 2 files changed, 23 insertions(+), 39 deletions(-) diff --git a/libafl_targets/build.rs b/libafl_targets/build.rs index 7950fe902e..1ec3934f64 100644 --- a/libafl_targets/build.rs +++ b/libafl_targets/build.rs @@ -19,10 +19,16 @@ fn main() { let mut sancov_cmp = cc::Build::new(); #[cfg(feature = "sancov_value_profile")] - sancov_cmp.define("SANCOV_VALUE_PROFILE", "1"); + { + sancov_cmp.define("SANCOV_VALUE_PROFILE", "1"); + println!("cargo:rerun-if-changed=src/value_profile.h"); + } #[cfg(feature = "sancov_cmplog")] - sancov_cmp.define("SANCOV_CMPLOG", "1"); + { + sancov_cmp.define("SANCOV_CMPLOG", "1"); + println!("cargo:rerun-if-changed=src/cmplog.h"); + } sancov_cmp .file(_src_dir.join("sancov_cmp.c")) diff --git a/libafl_targets/src/sancov_cmp.c b/libafl_targets/src/sancov_cmp.c index 2c2588e913..33cbd31daf 100644 --- a/libafl_targets/src/sancov_cmp.c +++ b/libafl_targets/src/sancov_cmp.c @@ -8,43 +8,6 @@ #include "cmplog.h" #endif -#if defined(__APPLE__) - -void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2); -void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2) { - __sanitizer_cov_trace_cmp1(arg1, arg2); -} - -void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2); -void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2) { - __sanitizer_cov_trace_cmp2(arg1, arg2); -} - -void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2); -void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2) { - __sanitizer_cov_trace_cmp4(arg1, arg2); -} - -void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2); -void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2) { - __sanitizer_cov_trace_cmp8(arg1, arg2); -} - -#elif defined(_MSC_VER) - #pragma comment(linker, "/alternatename:__sanitizer_cov_trace_const_cmp1=__sanitizer_cov_trace_cmp1") - #pragma comment(linker, "/alternatename:__sanitizer_cov_trace_const_cmp2=__sanitizer_cov_trace_cmp2") - #pragma comment(linker, "/alternatename:__sanitizer_cov_trace_const_cmp4=__sanitizer_cov_trace_cmp4") - #pragma comment(linker, "/alternatename:__sanitizer_cov_trace_const_cmp8=__sanitizer_cov_trace_cmp8") -#else -void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2) __attribute__((alias("__sanitizer_cov_trace_cmp1"))); -void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2) - __attribute__((alias("__sanitizer_cov_trace_cmp2"))); -void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2) - __attribute__((alias("__sanitizer_cov_trace_cmp4"))); -void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2) - __attribute__((alias("__sanitizer_cov_trace_cmp8"))); -#endif - void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) { uintptr_t k = RETADDR; @@ -147,3 +110,18 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { } +void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2) { + __sanitizer_cov_trace_cmp1(arg1, arg2); +} + +void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2) { + __sanitizer_cov_trace_cmp2(arg1, arg2); +} + +void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2) { + __sanitizer_cov_trace_cmp4(arg1, arg2); +} + +void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2) { + __sanitizer_cov_trace_cmp8(arg1, arg2); +} From 4271790cb50d8b390abe7d1d82ddd88f7e70c0d2 Mon Sep 17 00:00:00 2001 From: s1341 Date: Tue, 8 Jun 2021 10:54:38 +0300 Subject: [PATCH 5/8] Add unique_name() to Input. Use it to generate filename in OnDiskCorpus (#152) * Add unique_name() to Input. Use unique_name to generate filename in OnDiskCorpus * updated duplicate ahash * nostd fixes * fmt * rename unique_name to generate_name Co-authored-by: Dominik Maier --- fuzzers/frida_libpng/Cargo.toml | 1 - libafl/Cargo.toml | 3 ++- libafl/src/corpus/ondisk.rs | 8 +++++++- libafl/src/inputs/bytes.rs | 12 +++++++++++- libafl/src/inputs/mod.rs | 14 ++++++++++++-- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/fuzzers/frida_libpng/Cargo.toml b/fuzzers/frida_libpng/Cargo.toml index c6b48feeb1..589c202717 100644 --- a/fuzzers/frida_libpng/Cargo.toml +++ b/fuzzers/frida_libpng/Cargo.toml @@ -30,7 +30,6 @@ libc = "0.2" libloading = "0.7.0" num-traits = "0.2.14" rangemap = "0.1.10" -seahash = "4.1.0" clap = "2.33" serde = "1.0" diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 1cfa0b0796..9a5585d503 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -16,7 +16,7 @@ rustc_version = "0.3.3" [dev-dependencies] criterion = "0.3" # Benchmarking -ahash = "0.6.1" # another hash +ahash = "0.7" # another hash fxhash = "0.2.1" # yet another hash xxhash-rust = { version = "0.8.2", features = ["xxh3"] } # xxh3 hashing for rust serde_json = "1.0.60" @@ -68,6 +68,7 @@ core_affinity = { version = "0.5", git = "https://github.com/s1341/core_affinity num_enum = "0.5.1" hostname = "^0.3" # Is there really no gethostname in the stdlib? typed-builder = "0.9.0" +ahash ="0.7" [target.'cfg(target_os = "android")'.dependencies] backtrace = { version = "0.3", optional = true, default-features = false, features = ["std", "libbacktrace"] } # for llmp_debug diff --git a/libafl/src/corpus/ondisk.rs b/libafl/src/corpus/ondisk.rs index 15d7cbc277..8e9503846d 100644 --- a/libafl/src/corpus/ondisk.rs +++ b/libafl/src/corpus/ondisk.rs @@ -50,7 +50,13 @@ where fn add(&mut self, mut testcase: Testcase) -> Result { if testcase.filename().is_none() { // TODO walk entry metadata to ask for pices of filename (e.g. :havoc in AFL) - let filename = self.dir_path.join(format!("id_{}", &self.entries.len())); + let filename = self.dir_path.join( + testcase + .input() + .as_ref() + .unwrap() + .generate_name(self.entries.len()), + ); let filename_str = filename.to_str().expect("Invalid Path"); testcase.set_filename(filename_str.into()); }; diff --git a/libafl/src/inputs/bytes.rs b/libafl/src/inputs/bytes.rs index 2eb97a7e15..c07c2b509d 100644 --- a/libafl/src/inputs/bytes.rs +++ b/libafl/src/inputs/bytes.rs @@ -1,7 +1,10 @@ //! The `BytesInput` is the "normal" input, a map of bytes, that can be sent directly to the client //! (As opposed to other, more abstract, imputs, like an Grammar-Based AST Input) -use alloc::{borrow::ToOwned, rc::Rc, vec::Vec}; +use ahash::AHasher; +use core::hash::Hasher; + +use alloc::{borrow::ToOwned, rc::Rc, string::String, vec::Vec}; use core::{cell::RefCell, convert::From}; use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] @@ -48,6 +51,13 @@ impl Input for BytesInput { file.read_to_end(&mut bytes)?; Ok(BytesInput::new(bytes)) } + + /// Generate a name for this input + fn generate_name(&self, _idx: usize) -> String { + let mut hasher = AHasher::new_with_keys(0, 0); + hasher.write(self.bytes()); + format!("{:016x}", hasher.finish()) + } } /// Rc Ref-cell from Input diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 831ab8fa9f..d8448f9e63 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -3,7 +3,10 @@ pub mod bytes; pub use bytes::BytesInput; -use alloc::vec::Vec; +use alloc::{ + string::{String, ToString}, + vec::Vec, +}; use core::{clone::Clone, fmt::Debug}; #[cfg(feature = "std")] use std::{ @@ -53,12 +56,19 @@ pub trait Input: Clone + serde::Serialize + serde::de::DeserializeOwned + Debug fn from_file

(_path: P) -> Result { Err(Error::NotImplemented("Not supprted in no_std".into())) } + + /// Generate a name for this input + fn generate_name(&self, idx: usize) -> String; } /// An input for tests, mainly. There is no real use much else. #[derive(Copy, Clone, Serialize, Deserialize, Debug)] pub struct NopInput {} -impl Input for NopInput {} +impl Input for NopInput { + fn generate_name(&self, _idx: usize) -> String { + "nop-input".to_string() + } +} impl HasTargetBytes for NopInput { fn target_bytes(&self) -> OwnedSlice { OwnedSlice::Owned(vec![0]) From 24beae99f76187b2457a5cd951966237dc50edf7 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 8 Jun 2021 15:40:32 +0200 Subject: [PATCH 6/8] launchers without brokers (fixes #128) (#157) --- libafl/src/bolts/launcher.rs | 91 ++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 31 deletions(-) diff --git a/libafl/src/bolts/launcher.rs b/libafl/src/bolts/launcher.rs index 113c7d77b1..bcacf31796 100644 --- a/libafl/src/bolts/launcher.rs +++ b/libafl/src/bolts/launcher.rs @@ -36,6 +36,7 @@ use typed_builder::TypedBuilder; pub type LauncherClientFnRef<'a, I, OT, S, SP> = &'a mut dyn FnMut(Option, LlmpRestartingEventManager) -> Result<(), Error>; +const _AFL_LAUNCHER_CLIENT: &str = "AFL_LAUNCHER_CLIENT"; /// Provides a Launcher, which can be used to launch a fuzzing run on a specified list of cores #[cfg(feature = "std")] #[derive(TypedBuilder)] @@ -54,7 +55,7 @@ where stats: ST, /// The 'main' function to run for each client forked. This probably shouldn't return run_client: LauncherClientFnRef<'a, I, OT, S, SP>, - /// The broker port to use + /// The broker port to use (or to attach to, in case [`Self::with_broker`] is `false`) #[builder(default = 1337_u16)] broker_port: u16, /// The list of cores to run on @@ -66,6 +67,12 @@ where /// clusters. #[builder(default = None)] remote_broker_addr: Option, + /// If this launcher should spawn a new `broker` on `[Self::broker_port]` (default). + /// The reason you may not want this is, if you already have a [`Launcher`] + /// with a different configuration (for the same target) running on this machine. + /// Then, clients launched by this [`Launcher`] can connect to the original `broker`. + #[builder(default = true)] + spawn_broker: bool, } #[cfg(feature = "std")] @@ -128,23 +135,37 @@ where }; } } - #[cfg(feature = "std")] - println!("I am broker!!."); - // TODO we don't want always a broker here, thing about using different laucher process to spawn different configurations - RestartingMgr::::builder() - .shmem_provider(self.shmem_provider.clone()) - .stats(Some(self.stats.clone())) - .broker_port(self.broker_port) - .kind(ManagerKind::Broker) - .remote_broker_addr(self.remote_broker_addr) - .build() - .launch()?; + if self.spawn_broker { + #[cfg(feature = "std")] + println!("I am broker!!."); - // Broker exited. kill all clients. - for handle in &handles { - unsafe { - libc::kill(*handle, libc::SIGINT); + // TODO we don't want always a broker here, thing about using different laucher process to spawn different configurations + RestartingMgr::::builder() + .shmem_provider(self.shmem_provider.clone()) + .stats(Some(self.stats.clone())) + .broker_port(self.broker_port) + .kind(ManagerKind::Broker) + .remote_broker_addr(self.remote_broker_addr) + .build() + .launch()?; + + // Broker exited. kill all clients. + for handle in &handles { + unsafe { + libc::kill(*handle, libc::SIGINT); + } + } + } else { + for handle in &handles { + let mut status = 0; + println!("Not spawning broker (spawn_broker is false). Waiting for fuzzer children to exit..."); + unsafe { + libc::waitpid(*handle, &mut status, 0); + if status != 0 { + println!("Client with pid {} exited with status {}", handle, status); + } + } } } @@ -215,25 +236,33 @@ where Err(_) => panic!("Env variables are broken, received non-unicode!"), }; - #[cfg(feature = "std")] - println!("I am broker!!."); + if self.spawn_broker { + #[cfg(feature = "std")] + println!("I am broker!!."); - RestartingMgr::::builder() - .shmem_provider(self.shmem_provider.clone()) - .stats(Some(self.stats.clone())) - .broker_port(self.broker_port) - .kind(ManagerKind::Broker) - .remote_broker_addr(self.remote_broker_addr) - .build() - .launch()?; + RestartingMgr::::builder() + .shmem_provider(self.shmem_provider.clone()) + .stats(Some(self.stats.clone())) + .broker_port(self.broker_port) + .kind(ManagerKind::Broker) + .remote_broker_addr(self.remote_broker_addr) + .build() + .launch()?; - //broker exited. kill all clients. - for handle in &mut handles { - handle.kill()?; + //broker exited. kill all clients. + for handle in &mut handles { + handle.kill()?; + } + } else { + println!("Not spawning broker (spawn_broker is false). Waiting for fuzzer children to exit..."); + for handle in &mut handles { + let ecode = handle.wait()?; + if !ecode.success() { + println!("Client with handle {:?} exited with {:?}", handle, ecode); + } + } } Ok(()) } } - -const _AFL_LAUNCHER_CLIENT: &str = "AFL_LAUNCHER_CLIENT"; From cbf271d99f2763b610c8d3f7874a808fd471cc6f Mon Sep 17 00:00:00 2001 From: s1341 Date: Wed, 9 Jun 2021 07:35:44 +0300 Subject: [PATCH 7/8] Remove stray print --- libafl_frida/src/helper.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index d2bbafba1b..f294613376 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -725,7 +725,6 @@ impl<'a> FridaInstrumentationHelper<'a> { } #[cfg(target_arch = "x86_64")] { - println!("here"); writer.put_lea_reg_reg_offset(X86Register::Rsp, X86Register::Rsp, -(redzone_size)); writer.put_push_reg(X86Register::Rdi); writer.put_mov_reg_address( From 609939b5ec7b17d8b3967f0eaeaed0ce313a9c63 Mon Sep 17 00:00:00 2001 From: s1341 Date: Wed, 9 Jun 2021 10:36:15 +0300 Subject: [PATCH 8/8] Use rlimit_cur as rlimit_max is set to MAX_LONG --- libafl_frida/src/asan_rt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libafl_frida/src/asan_rt.rs b/libafl_frida/src/asan_rt.rs index 20f7682701..e0febf11cc 100644 --- a/libafl_frida/src/asan_rt.rs +++ b/libafl_frida/src/asan_rt.rs @@ -212,7 +212,7 @@ impl AsanRuntime { }; assert!(unsafe { getrlimit(RLIMIT_STACK, &mut stack_rlimit as *mut rlimit) } == 0); - stack_rlimit.rlim_max as usize + stack_rlimit.rlim_cur as usize } /// Get the maximum stack size for the current stack @@ -225,7 +225,7 @@ impl AsanRuntime { }; assert!(unsafe { getrlimit64(RLIMIT_STACK, &mut stack_rlimit as *mut rlimit64) } == 0); - stack_rlimit.rlim_max as usize + stack_rlimit.rlim_cur as usize } /// Determine the stack start, end for the currently running thread