generic map
This commit is contained in:
parent
9362224020
commit
1e611da35b
@ -58,7 +58,6 @@ use core::{
|
|||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
net::{TcpListener, TcpStream},
|
net::{TcpListener, TcpStream},
|
||||||
thread,
|
thread,
|
||||||
@ -68,7 +67,7 @@ use crate::utils::next_pow2;
|
|||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use super::shmem_translated::{AflShmem, ShMem};
|
use super::shmem::ShMem;
|
||||||
|
|
||||||
/// We'll start off with 256 megabyte maps per fuzzer client
|
/// We'll start off with 256 megabyte maps per fuzzer client
|
||||||
const LLMP_PREF_INITIAL_MAP_SIZE: usize = 1 << 28;
|
const LLMP_PREF_INITIAL_MAP_SIZE: usize = 1 << 28;
|
||||||
@ -119,7 +118,7 @@ where
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct LlmpReceiver<SH>
|
pub struct LlmpReceiver<SH>
|
||||||
where
|
where
|
||||||
SH: ShMem
|
SH: ShMem,
|
||||||
{
|
{
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
/// Pointer to the last meg this received
|
/// Pointer to the last meg this received
|
||||||
@ -150,6 +149,7 @@ where
|
|||||||
/// shared between one LlmpSender and one LlmpReceiver
|
/// shared between one LlmpSender and one LlmpReceiver
|
||||||
shmem: SH,
|
shmem: SH,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Message sent over the "wire"
|
/// Message sent over the "wire"
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
@ -178,7 +178,7 @@ impl LlmpMsg {
|
|||||||
|
|
||||||
/// Gets the buffer from this message as slice, with the corrent length.
|
/// Gets the buffer from this message as slice, with the corrent length.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_slice<SH: ShMem>(&self, map: &LlmpSharedMap<SH>) -> Result<&[u8], AflError> {
|
pub fn as_slice<SH: ShMem>(&self, map: &mut LlmpSharedMap<SH>) -> Result<&[u8], AflError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if self.in_map(map) {
|
if self.in_map(map) {
|
||||||
Ok(self.as_slice_unsafe())
|
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.
|
/// Returns true, if the pointer is, indeed, in the page of this shared map.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn in_map<SH: ShMem>(&self, map: &LlmpSharedMap<SH>) -> bool {
|
pub fn in_map<SH: ShMem>(&self, map: &mut LlmpSharedMap<SH>) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
let map_size = map.shmem.map().len();
|
let map_size = map.shmem.map().len();
|
||||||
let buf_ptr = self.buf.as_ptr();
|
let buf_ptr = self.buf.as_ptr();
|
||||||
@ -209,9 +209,6 @@ impl LlmpMsg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// An Llmp instance
|
/// An Llmp instance
|
||||||
pub enum LlmpConnection<SH>
|
pub enum LlmpConnection<SH>
|
||||||
where
|
where
|
||||||
@ -226,7 +223,10 @@ where
|
|||||||
IsClient { client: LlmpClient<SH> },
|
IsClient { client: LlmpClient<SH> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LlmpConnection<AflShmem> {
|
impl<SH> LlmpConnection<SH>
|
||||||
|
where
|
||||||
|
SH: ShMem,
|
||||||
|
{
|
||||||
/// Creates either a broker, if the tcp port is not bound, or a client, connected to this port.
|
/// 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<Self, AflError> {
|
pub fn on_port(port: u16) -> Result<Self, AflError> {
|
||||||
match TcpListener::bind(format!("127.0.0.1:{}", port)) {
|
match TcpListener::bind(format!("127.0.0.1:{}", port)) {
|
||||||
@ -268,7 +268,7 @@ impl LlmpConnection<AflShmem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Contents of the share mem pages, used by llmp internally
|
/// Contents of the share mem pages, used by llmp internally
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct LlmpPage {
|
pub struct LlmpPage {
|
||||||
pub sender: u32,
|
pub sender: u32,
|
||||||
@ -282,7 +282,7 @@ pub struct LlmpPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The broker (node 0)
|
/// The broker (node 0)
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct LlmpBroker<SH>
|
pub struct LlmpBroker<SH>
|
||||||
where
|
where
|
||||||
@ -307,7 +307,7 @@ pub enum LlmpMsgHookResult {
|
|||||||
/// Message payload when a client got added LLMP_TAG_CLIENT_ADDED_V1 */
|
/// Message payload when a client got added LLMP_TAG_CLIENT_ADDED_V1 */
|
||||||
/// This is an internal message!
|
/// This is an internal message!
|
||||||
/// LLMP_TAG_END_OF_PAGE_V1
|
/// LLMP_TAG_END_OF_PAGE_V1
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
struct LlmpPayloadSharedMapInfo {
|
struct LlmpPayloadSharedMapInfo {
|
||||||
pub map_size: usize,
|
pub map_size: usize,
|
||||||
@ -316,8 +316,8 @@ struct LlmpPayloadSharedMapInfo {
|
|||||||
|
|
||||||
/// Get sharedmem from a page
|
/// Get sharedmem from a page
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn shmem2page<SH: ShMem>(afl_shmem: &SH) -> *mut LlmpPage {
|
unsafe fn shmem2page<SH: ShMem>(afl_shmem: &mut SH) -> *mut LlmpPage {
|
||||||
afl_shmem.map().as_mut_ptr() as *mut LlmpPage
|
afl_shmem.map_mut().as_mut_ptr() as *mut LlmpPage
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return, if a msg is contained in the current page
|
/// 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
|
/// Initialize a new llmp_page. size should be relative to
|
||||||
/// llmp_page->messages
|
/// llmp_page->messages
|
||||||
unsafe fn _llmp_page_init(shmem: &mut AflShmem, sender: u32) {
|
unsafe fn _llmp_page_init<SH: ShMem>(shmem: &mut SH, sender: u32) {
|
||||||
|
let map_size = shmem.map().len();
|
||||||
let page = shmem2page(shmem);
|
let page = shmem2page(shmem);
|
||||||
(*page).sender = sender;
|
(*page).sender = sender;
|
||||||
ptr::write_volatile(&mut (*page).current_msg_id, 0);
|
ptr::write_volatile(&mut (*page).current_msg_id, 0);
|
||||||
(*page).max_alloc_size = 0;
|
(*page).max_alloc_size = 0;
|
||||||
// Don't forget to subtract our own header size
|
// 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).size_used = 0;
|
||||||
(*(*page).messages.as_mut_ptr()).message_id = 0;
|
(*(*page).messages.as_mut_ptr()).message_id = 0;
|
||||||
(*(*page).messages.as_mut_ptr()).tag = LLMP_TAG_UNSET;
|
(*(*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.
|
/// Get the next pointer and make sure it's in the current page, and has enough space.
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn llmp_next_msg_ptr_checked<SH: ShMem> (
|
unsafe fn llmp_next_msg_ptr_checked<SH: ShMem>(
|
||||||
map: &LlmpSharedMap<SH>,
|
map: &mut LlmpSharedMap<SH>,
|
||||||
last_msg: *const LlmpMsg,
|
last_msg: *const LlmpMsg,
|
||||||
alloc_size: usize,
|
alloc_size: usize,
|
||||||
) -> Result<*mut LlmpMsg, AflError> {
|
) -> 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
|
/// An actor on the sendin part of the shared map
|
||||||
impl LlmpSender<AflShmem> {
|
impl<SH> LlmpSender<SH>
|
||||||
|
where
|
||||||
|
SH: ShMem,
|
||||||
|
{
|
||||||
/// For non zero-copy, we want to get rid of old pages with duplicate messages in the client
|
/// 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.
|
/// 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.
|
/// The broker would have informed us by setting the save_to_unmap-flag.
|
||||||
unsafe fn prune_old_pages(&mut self) {
|
unsafe fn prune_old_pages(&mut self) {
|
||||||
// Exclude the current page by splitting of the last element for this iter
|
// Exclude the current page by splitting of the last element for this iter
|
||||||
let mut unmap_until_excl = 0;
|
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 {
|
if (*map.page()).save_to_unmap == 0 {
|
||||||
// The broker didn't read this page yet, no more pages to unmap.
|
// The broker didn't read this page yet, no more pages to unmap.
|
||||||
break;
|
break;
|
||||||
@ -429,7 +433,7 @@ impl LlmpSender<AflShmem> {
|
|||||||
/// So if alloc_next fails, create new page if necessary, use this function,
|
/// So if alloc_next fails, create new page if necessary, use this function,
|
||||||
/// place EOP, commit EOP, reset, alloc again on the new space.
|
/// place EOP, commit EOP, reset, alloc again on the new space.
|
||||||
unsafe fn alloc_eop(&mut self) -> Result<*mut LlmpMsg, AflError> {
|
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 page = map.page();
|
||||||
let last_msg = self.last_msg_sent;
|
let last_msg = self.last_msg_sent;
|
||||||
if (*page).size_used + EOP_MSG_SIZE > (*page).size_total {
|
if (*page).size_used + EOP_MSG_SIZE > (*page).size_total {
|
||||||
@ -437,7 +441,7 @@ impl LlmpSender<AflShmem> {
|
|||||||
(*page).size_used, (*page).size_total));
|
(*page).size_used, (*page).size_total));
|
||||||
}
|
}
|
||||||
let mut ret: *mut LlmpMsg = if !last_msg.is_null() {
|
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 {
|
} else {
|
||||||
(*page).messages.as_mut_ptr()
|
(*page).messages.as_mut_ptr()
|
||||||
};
|
};
|
||||||
@ -461,7 +465,7 @@ impl LlmpSender<AflShmem> {
|
|||||||
unsafe fn alloc_next_if_space(&mut self, buf_len: usize) -> Option<*mut LlmpMsg> {
|
unsafe fn alloc_next_if_space(&mut self, buf_len: usize) -> Option<*mut LlmpMsg> {
|
||||||
let buf_len_padded;
|
let buf_len_padded;
|
||||||
let mut complete_msg_size = llmp_align(size_of::<LlmpMsg>() + buf_len);
|
let mut complete_msg_size = llmp_align(size_of::<LlmpMsg>() + buf_len);
|
||||||
let map = self.out_maps.last().unwrap();
|
let map = self.out_maps.last_mut().unwrap();
|
||||||
let page = map.page();
|
let page = map.page();
|
||||||
let last_msg = self.last_msg_sent;
|
let last_msg = self.last_msg_sent;
|
||||||
/* DBG("XXX complete_msg_size %lu (h: %lu)\n", complete_msg_size, sizeof(llmp_message)); */
|
/* DBG("XXX complete_msg_size %lu (h: %lu)\n", complete_msg_size, sizeof(llmp_message)); */
|
||||||
@ -554,7 +558,7 @@ impl LlmpSender<AflShmem> {
|
|||||||
(*msg).message_id
|
(*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) {
|
if msg.is_null() || !llmp_msg_in_page(page, msg) {
|
||||||
return Err(AflError::Unknown(format!(
|
return Err(AflError::Unknown(format!(
|
||||||
"Llmp Message {:?} is null or not in current page",
|
"Llmp Message {:?} is null or not in current page",
|
||||||
@ -574,7 +578,10 @@ impl LlmpSender<AflShmem> {
|
|||||||
let old_map = self.out_maps.last_mut().unwrap().page();
|
let old_map = self.out_maps.last_mut().unwrap().page();
|
||||||
|
|
||||||
// Create a new shard page.
|
// Create a new shard page.
|
||||||
let new_map_shmem = LlmpSharedMap::<AflShmem>::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();
|
let mut new_map = new_map_shmem.page();
|
||||||
|
|
||||||
ptr::write_volatile(&mut (*new_map).current_msg_id, (*old_map).current_msg_id);
|
ptr::write_volatile(&mut (*new_map).current_msg_id, (*old_map).current_msg_id);
|
||||||
@ -626,7 +633,7 @@ impl LlmpSender<AflShmem> {
|
|||||||
pub unsafe fn cancel_send(&mut self, msg: *mut LlmpMsg) {
|
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,
|
/* 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); */
|
* 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;
|
(*msg).tag = LLMP_TAG_UNSET;
|
||||||
(*page).size_used -= (*msg).buf_len_padded as usize + size_of::<LlmpMsg>();
|
(*page).size_used -= (*msg).buf_len_padded as usize + size_of::<LlmpMsg>();
|
||||||
}
|
}
|
||||||
@ -682,7 +689,7 @@ where
|
|||||||
} else {
|
} else {
|
||||||
// We don't know how big the msg wants to be, assert at least the header has space.
|
// We don't know how big the msg wants to be, assert at least the header has space.
|
||||||
Some(llmp_next_msg_ptr_checked(
|
Some(llmp_next_msg_ptr_checked(
|
||||||
&self.current_recv_map,
|
&mut self.current_recv_map,
|
||||||
last_msg,
|
last_msg,
|
||||||
size_of::<LlmpMsg>(),
|
size_of::<LlmpMsg>(),
|
||||||
)?)
|
)?)
|
||||||
@ -691,7 +698,7 @@ where
|
|||||||
// Let's see what we go here.
|
// Let's see what we go here.
|
||||||
match ret {
|
match ret {
|
||||||
Some(msg) => {
|
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()));
|
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.
|
// Handle special, LLMP internal, messages.
|
||||||
@ -717,10 +724,11 @@ where
|
|||||||
// Mark the old page save to unmap, in case we didn't so earlier.
|
// Mark the old page save to unmap, in case we didn't so earlier.
|
||||||
ptr::write_volatile(&mut (*page).save_to_unmap, 1);
|
ptr::write_volatile(&mut (*page).save_to_unmap, 1);
|
||||||
// Map the new page. The old one should be unmapped by Drop
|
// Map the new page. The old one should be unmapped by Drop
|
||||||
self.current_recv_map = LlmpSharedMap::new_from_shm_str_buf(
|
self.current_recv_map =
|
||||||
&pageinfo_cpy.shm_str,
|
LlmpSharedMap::existing(SH::existing_map_by_shm_bytes(
|
||||||
pageinfo_cpy.map_size,
|
&pageinfo_cpy.shm_str,
|
||||||
)?;
|
pageinfo_cpy.map_size,
|
||||||
|
)?);
|
||||||
// Mark the new page save to unmap also (it's mapped by us, the broker now)
|
// 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);
|
ptr::write_volatile(&mut (*page).save_to_unmap, 1);
|
||||||
|
|
||||||
@ -770,7 +778,7 @@ where
|
|||||||
Some(msg) => Some((
|
Some(msg) => Some((
|
||||||
(*msg).sender,
|
(*msg).sender,
|
||||||
(*msg).tag,
|
(*msg).tag,
|
||||||
(*msg).as_slice(&self.current_recv_map)?,
|
(*msg).as_slice(&mut self.current_recv_map)?,
|
||||||
)),
|
)),
|
||||||
None => None,
|
None => None,
|
||||||
})
|
})
|
||||||
@ -785,77 +793,53 @@ where
|
|||||||
Ok((
|
Ok((
|
||||||
(*msg).sender,
|
(*msg).sender,
|
||||||
(*msg).tag,
|
(*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.
|
/// The page struct, placed on a shared mem instance.
|
||||||
impl LlmpSharedMap<AflShmem> {
|
/// A thin wrapper around a ShMem implementation, with special Llmp funcs
|
||||||
/// 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<Self, AflError> {
|
|
||||||
// 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<Self, AflError> {
|
|
||||||
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<Self, AflError> {
|
|
||||||
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 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<SH> LlmpSharedMap<SH>
|
impl<SH> LlmpSharedMap<SH>
|
||||||
where
|
where
|
||||||
SH: ShMem,
|
SH: ShMem,
|
||||||
{
|
{
|
||||||
|
/// Creates a new page, initializing the passed shared mem struct
|
||||||
/// Initialize from a shm_str with fixed len of 20
|
pub fn new(sender: u32, mut new_map: SH) -> Self {
|
||||||
pub fn new_from_shm_str_buf(&self, shm_str: &[u8; 20], map_size: usize) -> Result<Self, AflError> {
|
unsafe {
|
||||||
let shmem = self.shmem.new_from_shm_str_buf(shm_str, map_size)?;
|
_llmp_page_init(&mut new_map, sender);
|
||||||
// Not initializing the page here - the other side should have done it already!
|
}
|
||||||
Ok(Self { shmem })
|
Self { shmem: new_map }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_to_env(&self, env_name: String) -> Result<(), AflError> {
|
/// Maps and wraps an existing
|
||||||
let map_size = self.shmem.map().len();
|
pub fn existing(existing_map: SH) -> Self {
|
||||||
let map_env = self.shmem.shm_str() ;
|
Self {
|
||||||
let map_size_env = format!("{}_SIZE", map_env);
|
shmem: existing_map,
|
||||||
env::set_var(map_env, self.shmem.shm_str());
|
}
|
||||||
env::set_var(map_size_env, format!("{}", map_size));
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the unsafe ptr to this page, situated on the shared map
|
/// Get the unsafe ptr to this page, situated on the shared map
|
||||||
pub unsafe fn page(&self) -> *mut LlmpPage {
|
pub unsafe fn page(&mut self) -> *mut LlmpPage {
|
||||||
shmem2page(&self.shmem)
|
shmem2page(&mut self.shmem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The broker forwards all messages to its own bus-like broadcast map.
|
/// The broker forwards all messages to its own bus-like broadcast map.
|
||||||
/// It may intercept messages passing through.
|
/// It may intercept messages passing through.
|
||||||
impl LlmpBroker<AflShmem> {
|
impl<SH> LlmpBroker<SH>
|
||||||
|
where
|
||||||
|
SH: ShMem,
|
||||||
|
{
|
||||||
/// Create and initialize a new llmp_broker
|
/// Create and initialize a new llmp_broker
|
||||||
pub fn new() -> Result<Self, AflError> {
|
pub fn new() -> Result<Self, AflError> {
|
||||||
let broker = LlmpBroker {
|
let broker = LlmpBroker {
|
||||||
llmp_out: LlmpSender {
|
llmp_out: LlmpSender {
|
||||||
id: 0,
|
id: 0,
|
||||||
last_msg_sent: ptr::null_mut(),
|
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
|
// Broker never cleans up the pages so that new
|
||||||
// clients may join at any time
|
// clients may join at any time
|
||||||
keep_pages_forever: true,
|
keep_pages_forever: true,
|
||||||
@ -901,7 +885,6 @@ impl LlmpBroker<AflShmem> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// The broker walks all pages and looks for changes, then broadcasts them on
|
/// The broker walks all pages and looks for changes, then broadcasts them on
|
||||||
/// its own shared page, once.
|
/// its own shared page, once.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -941,11 +924,6 @@ impl LlmpBroker<AflShmem> {
|
|||||||
self.llmp_out.send_buf(tag, buf)
|
self.llmp_out.send_buf(tag, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LlmpBroker<AflShmem> {
|
|
||||||
|
|
||||||
|
|
||||||
/// Launches a thread using a tcp listener socket, on which new clients may connect to this broker
|
/// Launches a thread using a tcp listener socket, on which new clients may connect to this broker
|
||||||
/// Does so on the given port.
|
/// Does so on the given port.
|
||||||
pub fn launch_tcp_listener_on(
|
pub fn launch_tcp_listener_on(
|
||||||
@ -974,8 +952,11 @@ impl LlmpBroker<AflShmem> {
|
|||||||
let llmp_tcp_id = self.llmp_clients.len() as u32;
|
let llmp_tcp_id = self.llmp_clients.len() as u32;
|
||||||
|
|
||||||
// Tcp out map sends messages from background thread tcp server to foreground client
|
// Tcp out map sends messages from background thread tcp server to foreground client
|
||||||
let tcp_out_map = LlmpSharedMap::<AflShmem>::new(llmp_tcp_id, LLMP_PREF_INITIAL_MAP_SIZE)?;
|
let tcp_out_map = LlmpSharedMap::new(
|
||||||
let tcp_out_map_str = tcp_out_map.shmem.shm_str_buf();
|
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();
|
let tcp_out_map_size = tcp_out_map.shmem.map().len();
|
||||||
self.register_client(tcp_out_map);
|
self.register_client(tcp_out_map);
|
||||||
|
|
||||||
@ -983,9 +964,9 @@ impl LlmpBroker<AflShmem> {
|
|||||||
let mut new_client_sender = LlmpSender {
|
let mut new_client_sender = LlmpSender {
|
||||||
id: 0,
|
id: 0,
|
||||||
last_msg_sent: 0 as *mut LlmpMsg,
|
last_msg_sent: 0 as *mut LlmpMsg,
|
||||||
out_maps: vec![
|
out_maps: vec![LlmpSharedMap::existing(
|
||||||
LlmpSharedMap::from_name_slice(&tcp_out_map_str, tcp_out_map_size).unwrap(),
|
SH::existing_from_name(&tcp_out_map_str, tcp_out_map_size).unwrap(),
|
||||||
],
|
)],
|
||||||
// drop pages to the broker if it already read them
|
// drop pages to the broker if it already read them
|
||||||
keep_pages_forever: false,
|
keep_pages_forever: false,
|
||||||
};
|
};
|
||||||
@ -1032,26 +1013,91 @@ impl LlmpBroker<AflShmem> {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_new_page(shm_str_buf: &[u8; 20], map_size: usize) -> Result<LlmpSharedMap<AflShmem>, AflError> {
|
/// broker broadcast to its own page for all others to read */
|
||||||
LlmpSharedMap::from_name_slice(shm_str_buf, map_size)
|
#[inline]
|
||||||
|
unsafe fn handle_new_msgs<F>(
|
||||||
|
&mut self,
|
||||||
|
client_id: u32,
|
||||||
|
on_new_msg: &mut F,
|
||||||
|
) -> Result<(), AflError>
|
||||||
|
where
|
||||||
|
F: FnMut(u32, Tag, &[u8]) -> Result<LlmpMsgHookResult, AflError>,
|
||||||
|
{
|
||||||
|
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::<LlmpPayloadSharedMapInfo>() as u64 {
|
||||||
|
println!("Ignoring broken CLIENT_ADDED msg due to incorrect size. Expected {} but got {}",
|
||||||
|
(*msg).buf_len_padded,
|
||||||
|
size_of::<LlmpPayloadSharedMapInfo>()
|
||||||
|
);
|
||||||
|
} 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,
|
/// `n` clients connect to a broker. They share an outgoing map with the broker,
|
||||||
/// and get incoming messages from the shared broker bus
|
/// and get incoming messages from the shared broker bus
|
||||||
impl LlmpClient<AflShmem> {
|
impl<SH> LlmpClient<SH>
|
||||||
|
where
|
||||||
fn map_new_page(shm_str_buf: &[u8; 20], map_size: usize) -> Result<LlmpSharedMap<SH>, AflError> {
|
SH: ShMem,
|
||||||
panic!("End of page not handled!");
|
{
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new LlmpClient
|
/// Creates a new LlmpClient
|
||||||
pub fn new(initial_broker_map: LlmpSharedMap<SH>) -> Result<Self, AflError> {
|
pub fn new(initial_broker_map: LlmpSharedMap<SH>) -> Result<Self, AflError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
llmp_out: LlmpSender {
|
llmp_out: LlmpSender {
|
||||||
id: 0,
|
id: 0,
|
||||||
last_msg_sent: 0 as *mut LlmpMsg,
|
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
|
// drop pages to the broker if it already read them
|
||||||
keep_pages_forever: false,
|
keep_pages_forever: false,
|
||||||
},
|
},
|
||||||
@ -1125,86 +1171,9 @@ impl LlmpClient<AflShmem> {
|
|||||||
self.llmp_in.recv_buf_blocking()
|
self.llmp_in.recv_buf_blocking()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// broker broadcast to its own page for all others to read */
|
|
||||||
#[inline]
|
|
||||||
unsafe fn handle_new_msgs<F>(
|
|
||||||
&mut self,
|
|
||||||
client_id: u32,
|
|
||||||
on_new_msg: &mut F,
|
|
||||||
) -> Result<(), AflError>
|
|
||||||
where
|
|
||||||
F: FnMut(u32, Tag, &[u8]) -> Result<LlmpMsgHookResult, AflError>,
|
|
||||||
{
|
|
||||||
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::<LlmpPayloadSharedMapInfo>() as u64 {
|
|
||||||
println!("Ignoring broken CLIENT_ADDED msg due to incorrect size. Expected {} but got {}",
|
|
||||||
(*msg).buf_len_padded,
|
|
||||||
size_of::<LlmpPayloadSharedMapInfo>()
|
|
||||||
);
|
|
||||||
} 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<AflShmem> {
|
|
||||||
|
|
||||||
/// Creates a new LlmpClient, reading the map id and len from env
|
/// Creates a new LlmpClient, reading the map id and len from env
|
||||||
pub fn create_using_env(env_var: &str) -> Result<Self, AflError> {
|
pub fn create_using_env(env_var: &str) -> Result<Self, AflError> {
|
||||||
|
Self::new(LlmpSharedMap::existing(SH::existing_from_env(env_var)?))
|
||||||
let map_str = env::var(env_var)?;
|
|
||||||
let map_size = str::parse::<usize>(&env::var(format!("{}_SIZE", env_var))?)?;
|
|
||||||
Ok(Self::new(LlmpSharedMap::from_name(&map_str, map_size)?)?)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a LlmpClient, getting the ID from a given port
|
/// Create a LlmpClient, getting the ID from a given port
|
||||||
@ -1215,15 +1184,14 @@ impl LlmpClient<AflShmem> {
|
|||||||
let mut new_broker_map_str: [u8; 20] = Default::default();
|
let mut new_broker_map_str: [u8; 20] = Default::default();
|
||||||
stream.read_exact(&mut new_broker_map_str)?;
|
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,
|
&new_broker_map_str,
|
||||||
LLMP_PREF_INITIAL_MAP_SIZE,
|
LLMP_PREF_INITIAL_MAP_SIZE,
|
||||||
)?)?;
|
)?))?;
|
||||||
|
|
||||||
stream.write(ret.llmp_out.out_maps.first().unwrap().shmem.shm_str_buf())?;
|
stream.write(ret.llmp_out.out_maps.first().unwrap().shmem.shm_str_buf())?;
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -1231,6 +1199,8 @@ mod tests {
|
|||||||
|
|
||||||
use std::{thread::sleep, time::Duration};
|
use std::{thread::sleep, time::Duration};
|
||||||
|
|
||||||
|
use crate::events::shmem::AflShmem;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
LlmpConnection::{self, IsBroker, IsClient},
|
LlmpConnection::{self, IsBroker, IsClient},
|
||||||
LlmpMsgHookResult::ForwardToClients,
|
LlmpMsgHookResult::ForwardToClients,
|
||||||
@ -1239,7 +1209,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn llmp_connection() {
|
pub fn llmp_connection() {
|
||||||
let mut broker = match LlmpConnection::on_port(1337).unwrap() {
|
let mut broker = match LlmpConnection::<AflShmem>::on_port(1337).unwrap() {
|
||||||
IsClient { client: _ } => panic!("Could not bind to port as broker"),
|
IsClient { client: _ } => panic!("Could not bind to port as broker"),
|
||||||
IsBroker {
|
IsBroker {
|
||||||
broker,
|
broker,
|
||||||
@ -1248,7 +1218,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Add the first client (2nd, actually, because of the tcp listener client)
|
// 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::<AflShmem>::on_port(1337).unwrap() {
|
||||||
IsBroker {
|
IsBroker {
|
||||||
broker: _,
|
broker: _,
|
||||||
listener_thread: _,
|
listener_thread: _,
|
||||||
@ -1277,5 +1247,4 @@ mod tests {
|
|||||||
// We want at least the tcp and sender clients.
|
// We want at least the tcp and sender clients.
|
||||||
assert_eq!(broker.llmp_clients.len(), 2);
|
assert_eq!(broker.llmp_clients.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
// TODO: llmp can be no_std, if we abstract away page creation
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub mod llmp;
|
pub mod llmp;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub mod shmem_translated;
|
pub mod shmem;
|
||||||
|
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use shmem_translated::AflShmem;
|
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
use core::{marker::PhantomData, time};
|
use core::{marker::PhantomData, time};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use self::llmp::Tag;
|
use self::llmp::Tag;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use self::shmem::AflShmem;
|
||||||
use crate::corpus::Corpus;
|
use crate::corpus::Corpus;
|
||||||
use crate::executors::Executor;
|
use crate::executors::Executor;
|
||||||
use crate::feedbacks::FeedbacksTuple;
|
use crate::feedbacks::FeedbacksTuple;
|
||||||
|
@ -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<Self, AflError> {
|
|
||||||
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<Self, AflError> {
|
|
||||||
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<Self, AflError> {
|
|
||||||
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::<i32>()
|
|
||||||
.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;
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ Welcome to libAFL
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate static_assertions;
|
extern crate static_assertions;
|
||||||
|
|
||||||
@ -107,12 +106,3 @@ impl From<ParseIntError> for AflError {
|
|||||||
Self::Unknown(format!("Failed to parse Int: {:?}", err))
|
Self::Unknown(format!("Failed to parse Int: {:?}", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
#[test]
|
|
||||||
fn it_works() {
|
|
||||||
assert_eq!(2 + 2, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -46,10 +46,10 @@ pub extern "C" fn afl_libfuzzer_main() {
|
|||||||
|
|
||||||
let stats = SimpleStats::new(|s| println!("{}", s));
|
let stats = SimpleStats::new(|s| println!("{}", s));
|
||||||
|
|
||||||
///
|
// TODO
|
||||||
match LlmpFuzzInstance::from_env("FUZZER_ENV") {
|
/* match LlmpFuzzInstance::from_env("FUZZER_ENV") {
|
||||||
|
|
||||||
}
|
}*/
|
||||||
|
|
||||||
let mut mgr = LlmpEventManager::new_on_port(1337, stats).unwrap();
|
let mut mgr = LlmpEventManager::new_on_port(1337, stats).unwrap();
|
||||||
if mgr.is_broker() {
|
if mgr.is_broker() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user