added descriptions to llmp

This commit is contained in:
Dominik Maier 2021-01-13 19:02:43 +01:00
parent 004c3e3233
commit 567f981f5f
4 changed files with 201 additions and 6 deletions

View File

@ -57,6 +57,7 @@ use core::{
sync::atomic::{compiler_fence, Ordering},
time::Duration,
};
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use std::{
env,
@ -65,7 +66,7 @@ use std::{
thread,
};
use super::shmem::ShMem;
use super::shmem::{ShMem, ShMemDescription};
use crate::utils::next_pow2;
use crate::AflError;
@ -217,6 +218,16 @@ unsafe fn _llmp_next_msg_ptr(last_msg: *const LlmpMsg) -> *mut LlmpMsg {
.offset((*last_msg).buf_len_padded as isize) as *mut LlmpMsg;
}
/// Description of a shared map.
/// May be used to restore the map by id.
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct LlmpDescription {
/// Info about the SharedMap in use
shmem: ShMemDescription,
/// The last message sent or received, depnding on page type
last_message_offset: Option<u64>,
}
#[derive(Copy, Clone, Debug)]
/// Result of an LLMP Mesasge hook
pub enum LlmpMsgHookResult {
@ -327,6 +338,23 @@ where
}
}
/// Describe this in a reproducable fashion, if it's a client
pub fn describe(&self) -> Result<LlmpClientDescription, AflError> {
Ok(match self {
LlmpConnection::IsClient { client } => client.describe()?,
_ => todo!("Only client can be described atm."),
})
}
/// Recreate an existing client from the stored description
pub fn existing_client_from_description(
description: &LlmpClientDescription,
) -> Result<LlmpConnection<SH>, AflError> {
Ok(LlmpConnection::IsClient {
client: LlmpClient::existing_client_from_description(description)?,
})
}
/// Sends the given buffer over this connection, no matter if client or broker.
pub fn send_buf(&mut self, tag: Tag, buf: &[u8]) -> Result<(), AflError> {
match self {
@ -432,9 +460,6 @@ where
#[cfg(feature = "std")]
pub fn to_env(&self, env_name: &str) -> Result<(), AflError> {
let current_out_map = self.out_maps.last().unwrap();
// TODO: Make sure somebody else has mapped this
// current_out_map.await_read_blocking();
current_out_map.shmem.write_to_env(env_name)?;
current_out_map.msg_to_env(self.last_msg_sent, env_name)
}
@ -731,6 +756,28 @@ where
self.send(msg)
}
}
// Describe this cient in a way, that it can be restored later with `Self::on_existing_from_description`
pub fn describe(&self) -> Result<LlmpDescription, AflError> {
let map = self.out_maps.last().unwrap();
let last_message_offset = if self.last_msg_sent.is_null() {
None
} else {
Some(map.msg_to_offset(self.last_msg_sent)?)
};
Ok(LlmpDescription {
shmem: map.shmem.description(),
last_message_offset,
})
}
// Create this client on an existing map from the given description. acquired with `self.describe`
pub fn on_existing_from_description(description: &LlmpDescription) -> Result<Self, AflError> {
Self::on_existing_map(
SH::existing_from_description(&description.shmem)?,
description.last_message_offset,
)
}
}
/// Receiving end on a (unidirectional) sharedmap channel
@ -922,6 +969,28 @@ where
))
}
}
// Describe this cient in a way, that it can be restored later with `Self::on_existing_from_description`
pub fn describe(&self) -> Result<LlmpDescription, AflError> {
let map = &self.current_recv_map;
let last_message_offset = if self.last_msg_recvd.is_null() {
None
} else {
Some(map.msg_to_offset(self.last_msg_recvd)?)
};
Ok(LlmpDescription {
shmem: map.shmem.description(),
last_message_offset,
})
}
// Create this client on an existing map from the given description. acquired with `self.describe`
pub fn on_existing_from_description(description: &LlmpDescription) -> Result<Self, AflError> {
Self::on_existing_map(
SH::existing_from_description(&description.shmem)?,
description.last_message_offset,
)
}
}
/// A page wrapper
@ -1330,6 +1399,15 @@ where
}
}
/// A restorable client description
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct LlmpClientDescription {
/// Description of the sender
sender: LlmpDescription,
/// Description of the receiver
receiver: LlmpDescription,
}
/// Client side of LLMP
#[derive(Clone, Debug)]
pub struct LlmpClient<SH>
@ -1380,6 +1458,24 @@ where
self.receiver.to_env(&format!("{}_RECEIVER", env_name))
}
/// Describe this client in a way that it can be recreated, for example after crash
fn describe(&self) -> Result<LlmpClientDescription, AflError> {
Ok(LlmpClientDescription {
sender: self.sender.describe()?,
receiver: self.receiver.describe()?,
})
}
/// Create an existing client from description
fn existing_client_from_description(
description: &LlmpClientDescription,
) -> Result<Self, AflError> {
Ok(Self {
sender: LlmpSender::on_existing_from_description(&description.sender)?,
receiver: LlmpReceiver::on_existing_from_description(&description.receiver)?,
})
}
/// Waits for the sender to be save to unmap.
/// If a receiver is involved on the other side, this function should always be called.
pub fn await_save_to_unmap_blocking(&self) {

View File

@ -12,7 +12,7 @@ use core::{
use serde::{Deserialize, Serialize};
use self::{
llmp::{LlmpClient, Tag},
llmp::{LlmpClient, LlmpClientDescription, Tag},
shmem::ShMem,
};
use crate::{
@ -800,6 +800,25 @@ where
})
}
/// Describe the client event mgr's llmp parts in a restorable fashion
pub fn describe(&self) -> Result<LlmpClientDescription, AflError> {
self.llmp.describe()
}
/// Create an existing client from description
pub fn existing_client_from_description(
description: &LlmpClientDescription,
stats: ST,
) -> Result<Self, AflError> {
Ok(Self {
llmp: llmp::LlmpConnection::existing_client_from_description(description)?,
// Inserting a nop-stats element here so rust won't complain.
// In any case, the client won't currently use it.
stats: stats,
phantom: PhantomData,
})
}
/// A client on an existing map
pub fn for_client(client: LlmpClient<SH>, stats: ST) -> Self {
Self {
@ -860,6 +879,7 @@ where
}
}
/// Send an event kind via llmp
#[inline]
fn send_event_kind<'a>(&mut self, event: LLMPEventKind<'a, I>) -> Result<(), AflError> {
let serialized = postcard::to_allocvec(&event)?;

View File

@ -6,11 +6,22 @@ pub use shmem::AflShmem;
use alloc::string::{String, ToString};
use core::fmt::Debug;
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use std::env;
use crate::AflError;
/// Description of a shared map.
/// May be used to restore the map by id.
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct ShMemDescription {
/// Size of this map
size: usize,
/// of name of this map, as fixed 20 bytes c-string
str_bytes: [u8; 20],
}
/// A Shared map
pub trait ShMem: Sized + Debug {
/// Creates a new map with the given size
@ -52,6 +63,19 @@ pub trait ShMem: Sized + Debug {
/// The actual shared map, mutable
fn map_mut(&mut self) -> &mut [u8];
/// Describe this shared map in a recreatable fashion
fn description(&self) -> ShMemDescription {
ShMemDescription {
size: self.map().len(),
str_bytes: self.shm_slice().clone(),
}
}
/// Create a map from a map description
fn existing_from_description(description: &ShMemDescription) -> Result<Self, AflError> {
Self::existing_from_shm_slice(&description.str_bytes, description.size)
}
/// Write this map's config to env
#[cfg(feature = "std")]
fn write_to_env(&self, env_name: &str) -> Result<(), AflError> {

View File

@ -8,10 +8,65 @@ use xxhash_rust::xxh3::xxh3_64_with_seed;
#[cfg(feature = "std")]
use std::time::{SystemTime, UNIX_EPOCH};
use crate::{corpus::Corpus, engines::State, feedbacks::FeedbacksTuple, inputs::Input, AflError};
use crate::{
corpus::Corpus,
engines::State,
events::{shmem::ShMem, LlmpEventManager, Stats},
feedbacks::FeedbacksTuple,
inputs::Input,
AflError,
};
pub type StdRand = RomuTrioRand;
/// Serialize the current state and corpus during an executiont to bytes.
/// On top, add the current llmp event manager instance to be restored
/// This method is needed when the fuzzer run crashes and has to restart.
pub fn serialize_state_corpus_mgr<C, FT, I, R, SH, ST>(
state: &State<I, R, FT>,
corpus: &C,
mgr: &LlmpEventManager<I, SH, ST>,
) -> Result<Vec<u8>, AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
I: Input,
R: Rand,
SH: ShMem,
ST: Stats,
{
let mgr_bytes = postcard::to_allocvec(&mgr.describe()?)?;
let state_bytes = postcard::to_allocvec(&state)?;
let corpus_bytes = postcard::to_allocvec(&corpus)?;
Ok(postcard::to_allocvec(&(
state_bytes,
corpus_bytes,
mgr_bytes,
))?)
}
/// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)`
pub fn deserialize_state_corpus_mgr<C, FT, I, R, SH, ST>(
state_corpus_serialized: &[u8],
stats: ST,
) -> Result<(State<I, R, FT>, C, LlmpEventManager<I, SH, ST>), AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
I: Input,
R: Rand,
SH: ShMem,
ST: Stats,
{
let tuple: (Vec<u8>, Vec<u8>, Vec<u8>) = postcard::from_bytes(&state_corpus_serialized)?;
let client_description = postcard::from_bytes(&tuple.2)?;
Ok((
postcard::from_bytes(&tuple.0)?,
postcard::from_bytes(&tuple.1)?,
LlmpEventManager::existing_client_from_description(&client_description, stats)?,
))
}
/// Serialize the current state and corpus during an executiont to bytes.
/// This method is needed when the fuzzer run crashes and has to restart.
pub fn serialize_state_corpus<C, FT, I, R>(