added descriptions to llmp
This commit is contained in:
parent
004c3e3233
commit
567f981f5f
@ -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) {
|
||||
|
@ -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)?;
|
||||
|
@ -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> {
|
||||
|
@ -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>(
|
||||
|
Loading…
x
Reference in New Issue
Block a user