safer llmp
This commit is contained in:
parent
999e7023e4
commit
2265d91169
@ -56,14 +56,14 @@ unsafe fn broker_message_hook(
|
|||||||
println!(
|
println!(
|
||||||
"Client {:?} sent message: {:?}",
|
"Client {:?} sent message: {:?}",
|
||||||
client_id,
|
client_id,
|
||||||
u32::from_le_bytes((*message).as_slice().try_into().unwrap())
|
u32::from_le_bytes((*message).as_slice_unsafe().try_into().unwrap())
|
||||||
);
|
);
|
||||||
llmp::LlmpMsgHookResult::ForwardToClients
|
llmp::LlmpMsgHookResult::ForwardToClients
|
||||||
}
|
}
|
||||||
TAG_MATH_RESULT_V1 => {
|
TAG_MATH_RESULT_V1 => {
|
||||||
println!(
|
println!(
|
||||||
"Adder Client has this current result: {:?}",
|
"Adder Client has this current result: {:?}",
|
||||||
u32::from_le_bytes((*message).as_slice().try_into().unwrap())
|
u32::from_le_bytes((*message).as_slice_unsafe().try_into().unwrap())
|
||||||
);
|
);
|
||||||
llmp::LlmpMsgHookResult::Handled
|
llmp::LlmpMsgHookResult::Handled
|
||||||
}
|
}
|
||||||
|
@ -158,8 +158,38 @@ pub struct LlmpMsg {
|
|||||||
/// The message we receive
|
/// The message we receive
|
||||||
impl LlmpMsg {
|
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.
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
/// This is unsafe if somebody has access to shared mem pages on the system.
|
||||||
unsafe { slice::from_raw_parts(self.buf.as_ptr(), self.buf_len as usize) }
|
pub unsafe fn as_slice_unsafe(&self) -> &[u8] {
|
||||||
|
slice::from_raw_parts(self.buf.as_ptr(), self.buf_len as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the buffer from this message as slice, with the corrent length.
|
||||||
|
pub fn as_slice(&self, map: &LlmpSharedMap) -> Result<&[u8], AflError> {
|
||||||
|
unsafe {
|
||||||
|
if self.in_map(map) {
|
||||||
|
Ok(self.as_slice_unsafe())
|
||||||
|
} else {
|
||||||
|
Err(AflError::IllegalState("Current message not in page. The sharedmap get tampered with or we have a BUG.".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true, if the pointer is, indeed, in the page of this shared map.
|
||||||
|
pub fn in_map(&self, map: &LlmpSharedMap) -> bool {
|
||||||
|
unsafe {
|
||||||
|
let buf_ptr = self.buf.as_ptr();
|
||||||
|
if buf_ptr > (map.page() as *const u8).offset(size_of::<LlmpPage>() as isize)
|
||||||
|
&& buf_ptr
|
||||||
|
<= (map.page() as *const u8)
|
||||||
|
.offset((map.shmem.map_size - size_of::<LlmpMsg>() as usize) as isize)
|
||||||
|
{
|
||||||
|
// The message header is in the page. Continue with checking the body.
|
||||||
|
let len = self.buf_len_padded as usize + size_of::<LlmpMsg>();
|
||||||
|
buf_ptr <= (map.page() as *const u8).offset((map.shmem.map_size - len) as isize)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,6 +294,29 @@ unsafe fn _llmp_page_init(shmem: &mut AflShmem, sender: u32) {
|
|||||||
ptr::write_volatile(&mut (*page).sender_dead, 0);
|
ptr::write_volatile(&mut (*page).sender_dead, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the next pointer and make sure it's in the current page, and has enough space.
|
||||||
|
#[inline]
|
||||||
|
unsafe fn llmp_next_msg_ptr_checked(
|
||||||
|
map: &LlmpSharedMap,
|
||||||
|
last_msg: *const LlmpMsg,
|
||||||
|
alloc_size: usize,
|
||||||
|
) -> Result<*mut LlmpMsg, AflError> {
|
||||||
|
let page = map.page();
|
||||||
|
let msg_begin_min = (page as *const u8).offset(size_of::<LlmpPage>() as isize);
|
||||||
|
// We still need space for this msg (alloc_size).
|
||||||
|
let msg_begin_max = (page as *const u8).offset((map.shmem.map_size - alloc_size) as isize);
|
||||||
|
let next = _llmp_next_msg_ptr(last_msg);
|
||||||
|
let next_ptr = next as *const u8;
|
||||||
|
if next_ptr >= msg_begin_min && next_ptr <= msg_begin_max {
|
||||||
|
Ok(next)
|
||||||
|
} else {
|
||||||
|
Err(AflError::IllegalState(format!(
|
||||||
|
"Inconsistent data on sharedmap, or Bug (next_ptr was {:x}, sharedmap page was {:x})",
|
||||||
|
next_ptr as usize, page as usize
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Pointer to the message behind the last message
|
/// Pointer to the message behind the last message
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn _llmp_next_msg_ptr(last_msg: *const LlmpMsg) -> *mut LlmpMsg {
|
unsafe fn _llmp_next_msg_ptr(last_msg: *const LlmpMsg) -> *mut LlmpMsg {
|
||||||
@ -297,15 +350,16 @@ impl LlmpSender {
|
|||||||
/// The normal alloc will fail if there is not enough space for buf_len_padded + EOP
|
/// The normal alloc will fail if there is not enough space for buf_len_padded + EOP
|
||||||
/// 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) -> *mut LlmpMsg {
|
unsafe fn alloc_eop(&mut self) -> Result<*mut LlmpMsg, AflError> {
|
||||||
let page = self.out_maps.last().unwrap().page();
|
let map = self.out_maps.last().unwrap();
|
||||||
|
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 {
|
||||||
panic!(format!("PROGRAM ABORT : BUG: EOP does not fit in page! page {:?}, size_current {:?}, size_total {:?}", page,
|
panic!(format!("PROGRAM ABORT : BUG: EOP does not fit in page! page {:?}, size_current {:?}, size_total {:?}", page,
|
||||||
(*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(last_msg)
|
llmp_next_msg_ptr_checked(&map, last_msg, EOP_MSG_SIZE)?
|
||||||
} else {
|
} else {
|
||||||
(*page).messages.as_mut_ptr()
|
(*page).messages.as_mut_ptr()
|
||||||
};
|
};
|
||||||
@ -320,7 +374,7 @@ impl LlmpSender {
|
|||||||
};
|
};
|
||||||
(*ret).tag = LLMP_TAG_END_OF_PAGE;
|
(*ret).tag = LLMP_TAG_END_OF_PAGE;
|
||||||
(*page).size_used += EOP_MSG_SIZE;
|
(*page).size_used += EOP_MSG_SIZE;
|
||||||
ret
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Intern: Will return a ptr to the next msg buf, or None if map is full.
|
/// Intern: Will return a ptr to the next msg buf, or None if map is full.
|
||||||
@ -329,7 +383,8 @@ impl LlmpSender {
|
|||||||
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 mut buf_len_padded = buf_len;
|
let mut buf_len_padded = buf_len;
|
||||||
let mut complete_msg_size = llmp_align(size_of::<LlmpMsg>() + buf_len_padded);
|
let mut complete_msg_size = llmp_align(size_of::<LlmpMsg>() + buf_len_padded);
|
||||||
let page = self.out_maps.last().unwrap().page();
|
let map = self.out_maps.last().unwrap();
|
||||||
|
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)); */
|
||||||
/* In case we don't have enough space, make sure the next page will be large
|
/* In case we don't have enough space, make sure the next page will be large
|
||||||
@ -376,7 +431,13 @@ impl LlmpSender {
|
|||||||
/* We're full. */
|
/* We're full. */
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
ret = _llmp_next_msg_ptr(last_msg);
|
ret = match llmp_next_msg_ptr_checked(map, last_msg, complete_msg_size) {
|
||||||
|
Ok(msg) => msg,
|
||||||
|
Err(e) => {
|
||||||
|
dbg!("Unexpected error allocing new msg", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
(*ret).message_id = (*last_msg).message_id + 1
|
(*ret).message_id = (*last_msg).message_id + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,7 +502,7 @@ impl LlmpSender {
|
|||||||
(*new_map).max_alloc_size = (*old_map).max_alloc_size;
|
(*new_map).max_alloc_size = (*old_map).max_alloc_size;
|
||||||
/* On the old map, place a last message linking to the new map for the clients
|
/* On the old map, place a last message linking to the new map for the clients
|
||||||
* to consume */
|
* to consume */
|
||||||
let mut out: *mut LlmpMsg = self.alloc_eop();
|
let mut out: *mut LlmpMsg = self.alloc_eop()?;
|
||||||
(*out).sender = (*old_map).sender;
|
(*out).sender = (*old_map).sender;
|
||||||
|
|
||||||
let mut end_of_page_msg = (*out).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo;
|
let mut end_of_page_msg = (*out).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo;
|
||||||
@ -535,12 +596,20 @@ impl LlmpReceiver {
|
|||||||
/* Oops! No new message! */
|
/* Oops! No new message! */
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(_llmp_next_msg_ptr(last_msg))
|
// We don't know how big the msg wants to be, assert at least the header has space.
|
||||||
|
Some(llmp_next_msg_ptr_checked(
|
||||||
|
&self.current_recv_map,
|
||||||
|
last_msg,
|
||||||
|
size_of::<LlmpMsg>(),
|
||||||
|
)?)
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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) {
|
||||||
|
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.
|
||||||
match (*msg).tag {
|
match (*msg).tag {
|
||||||
LLMP_TAG_UNSET => panic!("BUG: Read unallocated msg"),
|
LLMP_TAG_UNSET => panic!("BUG: Read unallocated msg"),
|
||||||
@ -561,11 +630,16 @@ impl LlmpReceiver {
|
|||||||
Clone the contents first to be safe (probably fine in rust eitner way). */
|
Clone the contents first to be safe (probably fine in rust eitner way). */
|
||||||
let pageinfo_cpy = (*pageinfo).clone();
|
let pageinfo_cpy = (*pageinfo).clone();
|
||||||
|
|
||||||
|
// 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
|
||||||
self.current_recv_map = LlmpSharedMap::from_name_slice(
|
self.current_recv_map = LlmpSharedMap::from_name_slice(
|
||||||
&pageinfo_cpy.shm_str,
|
&pageinfo_cpy.shm_str,
|
||||||
pageinfo_cpy.map_size,
|
pageinfo_cpy.map_size,
|
||||||
)?;
|
)?;
|
||||||
|
// Mark the new page save to unmap also (it's mapped by us, the broker now)
|
||||||
|
ptr::write_volatile(&mut (*page).save_to_unmap, 1);
|
||||||
|
|
||||||
dbg!("Got a new recv map", self.current_recv_map.shmem.shm_str);
|
dbg!("Got a new recv map", self.current_recv_map.shmem.shm_str);
|
||||||
// After we mapped the new page, return the next message, if available
|
// After we mapped the new page, return the next message, if available
|
||||||
return self.recv();
|
return self.recv();
|
||||||
@ -608,7 +682,7 @@ impl LlmpReceiver {
|
|||||||
pub fn recv_buf(&mut self) -> Result<Option<(u32, &[u8])>, AflError> {
|
pub fn recv_buf(&mut self) -> Result<Option<(u32, &[u8])>, AflError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
Ok(match self.recv()? {
|
Ok(match self.recv()? {
|
||||||
Some(msg) => Some(((*msg).tag, (*msg).as_slice())),
|
Some(msg) => Some(((*msg).tag, (*msg).as_slice(&self.current_recv_map)?)),
|
||||||
None => None,
|
None => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -618,7 +692,7 @@ impl LlmpReceiver {
|
|||||||
pub fn recv_buf_blocking(&mut self) -> Result<(u32, &[u8]), AflError> {
|
pub fn recv_buf_blocking(&mut self) -> Result<(u32, &[u8]), AflError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let msg = self.recv_blocking()?;
|
let msg = self.recv_blocking()?;
|
||||||
Ok(((*msg).tag, (*msg).as_slice()))
|
Ok(((*msg).tag, (*msg).as_slice(&self.current_recv_map)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
mod llmp;
|
pub mod llmp;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub mod shmem_translated;
|
pub mod shmem_translated;
|
||||||
|
|
||||||
@ -534,10 +534,10 @@ where
|
|||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::events::Event;
|
use crate::events::Event;
|
||||||
use crate::serde_anymap::{Ptr, PtrMut};
|
|
||||||
use crate::inputs::bytes::BytesInput;
|
use crate::inputs::bytes::BytesInput;
|
||||||
use crate::observers::{Observer, StdMapObserver};
|
|
||||||
use crate::observers::observer_serde::NamedSerdeAnyMap;
|
use crate::observers::observer_serde::NamedSerdeAnyMap;
|
||||||
|
use crate::observers::{Observer, StdMapObserver};
|
||||||
|
use crate::serde_anymap::{Ptr, PtrMut};
|
||||||
|
|
||||||
static mut MAP: [u32; 4] = [0; 4];
|
static mut MAP: [u32; 4] = [0; 4];
|
||||||
|
|
||||||
@ -563,10 +563,13 @@ mod tests {
|
|||||||
input: _,
|
input: _,
|
||||||
observers: obs,
|
observers: obs,
|
||||||
} => {
|
} => {
|
||||||
let o = obs.as_ref().get::<StdMapObserver<u32>>(&"key".to_string()).unwrap();
|
let o = obs
|
||||||
|
.as_ref()
|
||||||
|
.get::<StdMapObserver<u32>>(&"key".to_string())
|
||||||
|
.unwrap();
|
||||||
assert_eq!("test".to_string(), *o.name());
|
assert_eq!("test".to_string(), *o.name());
|
||||||
},
|
}
|
||||||
_ => panic!("mistmatch".to_string())
|
_ => panic!("mistmatch".to_string()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ pub trait Input: Clone + serde::Serialize + serde::de::DeserializeOwned {
|
|||||||
{
|
{
|
||||||
let mut file = File::create(path)?;
|
let mut file = File::create(path)?;
|
||||||
let serialized = postcard::to_allocvec(self)?;
|
let serialized = postcard::to_allocvec(self)?;
|
||||||
file.write_all(&serialized);
|
file.write_all(&serialized)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,7 +450,7 @@ impl<'a, T: 'a + ?Sized + serde::Serialize> serde::Serialize for Ptr<'a, T> {
|
|||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
Ptr::Ref(ref r) => se.serialize_some(r),
|
Ptr::Ref(ref r) => se.serialize_some(r),
|
||||||
Ptr::Owned(ref b) => se.serialize_some(b.as_ref())
|
Ptr::Owned(ref b) => se.serialize_some(b.as_ref()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -474,7 +474,6 @@ impl<'a, T: Sized> Ptr<'a, T> {
|
|||||||
Ptr::Owned(v) => v.as_ref(),
|
Ptr::Owned(v) => v.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum PtrMut<'a, T: 'a + ?Sized> {
|
pub enum PtrMut<'a, T: 'a + ?Sized> {
|
||||||
@ -489,7 +488,7 @@ impl<'a, T: 'a + ?Sized + serde::Serialize> serde::Serialize for PtrMut<'a, T> {
|
|||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
PtrMut::Ref(ref r) => se.serialize_some(r),
|
PtrMut::Ref(ref r) => se.serialize_some(r),
|
||||||
PtrMut::Owned(ref b) => se.serialize_some(b.as_ref())
|
PtrMut::Owned(ref b) => se.serialize_some(b.as_ref()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -522,7 +521,6 @@ impl<'a, T: Sized> PtrMut<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub enum Slice<'a, T: 'a + Sized> {
|
pub enum Slice<'a, T: 'a + Sized> {
|
||||||
Ref(&'a [T]),
|
Ref(&'a [T]),
|
||||||
Owned(Vec<T>),
|
Owned(Vec<T>),
|
||||||
@ -535,7 +533,7 @@ impl<'a, T: 'a + Sized + serde::Serialize> serde::Serialize for Slice<'a, T> {
|
|||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
Slice::Ref(ref r) => se.serialize_some(r),
|
Slice::Ref(ref r) => se.serialize_some(r),
|
||||||
Slice::Owned(ref b) => se.serialize_some(b.as_slice())
|
Slice::Owned(ref b) => se.serialize_some(b.as_slice()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -573,7 +571,7 @@ impl<'a, T: 'a + Sized + serde::Serialize> serde::Serialize for SliceMut<'a, T>
|
|||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
SliceMut::Ref(ref r) => se.serialize_some(r),
|
SliceMut::Ref(ref r) => se.serialize_some(r),
|
||||||
SliceMut::Owned(ref b) => se.serialize_some(b.as_slice())
|
SliceMut::Owned(ref b) => se.serialize_some(b.as_slice()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user