pub struct BudgetedReader<R> { /* private fields */ }Expand description
A reader wrapper that enforces a byte budget during deserialization.
§Threat Model
Malicious input can attack deserialization in two ways:
- Fake length prefix: Input claims
len = 2^60elements, causing allocation of a hugeVecbefore any data is read. - Oversized input: Attacker sends gigabytes of valid-looking data to exhaust memory over time.
§Defense Strategy
Use BudgetedReader to limit total bytes consumed. Its max_alloc
method derives a bound from the remaining budget, which
read_many_iter checks before iterating.
§Problem: SliceReader alone doesn’t bound allocations
use miden_serde_utils::{ByteReader, Deserializable, SliceReader};
// Malicious input: length prefix says 1 billion u64s, but only 16 bytes of data
let mut data = Vec::new();
data.push(0u8); // vint64 9-byte marker
data.extend_from_slice(&1_000_000_000u64.to_le_bytes());
data.extend_from_slice(&[0u8; 16]);
// SliceReader returns usize::MAX from max_alloc, so read_many_iter accepts
// any length. This would try to iterate 1 billion times (slow, not OOM,
// but still a DoS vector).
let reader = SliceReader::new(&data);
assert_eq!(reader.max_alloc(8), usize::MAX);§Solution: BudgetedReader bounds allocations via max_alloc
use miden_serde_utils::{BudgetedReader, ByteReader, Deserializable, SliceReader};
// Same malicious input
let mut data = Vec::new();
data.push(0u8);
data.extend_from_slice(&1_000_000_000u64.to_le_bytes());
data.extend_from_slice(&[0u8; 16]);
// BudgetedReader with 64-byte budget: max_alloc(8) = 64/8 = 8 elements
let inner = SliceReader::new(&data);
let reader = BudgetedReader::new(inner, 64);
assert_eq!(reader.max_alloc(8), 8);
// read_many_iter rejects the 1B length since 1B > 8
let result = Vec::<u64>::read_from_bytes_with_budget(&data, 64);
assert!(result.is_err());§Best practice: Set budget to expected input size
use miden_serde_utils::{ByteWriter, Deserializable, Serializable};
// Legitimate input: 3 u64s, properly serialized
let original = vec![1u64, 2, 3];
let mut data = Vec::new();
original.write_into(&mut data);
// Budget = data.len() bounds both fake lengths and total consumption
let result = Vec::<u64>::read_from_bytes_with_budget(&data, data.len());
assert_eq!(result.unwrap(), vec![1, 2, 3]);Implementations§
Trait Implementations§
Source§impl<R: ByteReader> ByteReader for BudgetedReader<R>
impl<R: ByteReader> ByteReader for BudgetedReader<R>
Source§fn read_u8(&mut self) -> Result<u8, DeserializationError>
fn read_u8(&mut self) -> Result<u8, DeserializationError>
Returns a single byte read from
self. Read moreSource§fn peek_u8(&self) -> Result<u8, DeserializationError>
fn peek_u8(&self) -> Result<u8, DeserializationError>
Returns the next byte to be read from
self without advancing the reader to the next byte. Read moreSource§fn read_slice(&mut self, len: usize) -> Result<&[u8], DeserializationError>
fn read_slice(&mut self, len: usize) -> Result<&[u8], DeserializationError>
Returns a slice of bytes of the specified length read from
self. Read moreSource§fn read_array<const N: usize>(
&mut self,
) -> Result<[u8; N], DeserializationError>
fn read_array<const N: usize>( &mut self, ) -> Result<[u8; N], DeserializationError>
Source§fn check_eor(&self, num_bytes: usize) -> Result<(), DeserializationError>
fn check_eor(&self, num_bytes: usize) -> Result<(), DeserializationError>
Checks if it is possible to read at least
num_bytes bytes from this ByteReader Read moreSource§fn has_more_bytes(&self) -> bool
fn has_more_bytes(&self) -> bool
Returns true if there are more bytes left to be read from
self.Source§fn max_alloc(&self, element_size: usize) -> usize
fn max_alloc(&self, element_size: usize) -> usize
Returns the maximum number of elements that can be safely allocated, given each
element occupies
element_size bytes when serialized. Read moreSource§fn read_bool(&mut self) -> Result<bool, DeserializationError>
fn read_bool(&mut self) -> Result<bool, DeserializationError>
Returns a boolean value read from
self consuming 1 byte from the reader. Read moreSource§fn read_u16(&mut self) -> Result<u16, DeserializationError>
fn read_u16(&mut self) -> Result<u16, DeserializationError>
Returns a u16 value read from
self in little-endian byte order. Read moreSource§fn read_u32(&mut self) -> Result<u32, DeserializationError>
fn read_u32(&mut self) -> Result<u32, DeserializationError>
Returns a u32 value read from
self in little-endian byte order. Read moreSource§fn read_u64(&mut self) -> Result<u64, DeserializationError>
fn read_u64(&mut self) -> Result<u64, DeserializationError>
Returns a u64 value read from
self in little-endian byte order. Read moreSource§fn read_u128(&mut self) -> Result<u128, DeserializationError>
fn read_u128(&mut self) -> Result<u128, DeserializationError>
Returns a u128 value read from
self in little-endian byte order. Read moreSource§fn read_usize(&mut self) -> Result<usize, DeserializationError>
fn read_usize(&mut self) -> Result<usize, DeserializationError>
Source§fn read_vec(&mut self, len: usize) -> Result<Vec<u8>, DeserializationError>
fn read_vec(&mut self, len: usize) -> Result<Vec<u8>, DeserializationError>
Returns a byte vector of the specified length read from
self. Read moreSource§fn read_string(
&mut self,
num_bytes: usize,
) -> Result<String, DeserializationError>
fn read_string( &mut self, num_bytes: usize, ) -> Result<String, DeserializationError>
Returns a String of the specified length read from
self. Read moreSource§fn read<D>(&mut self) -> Result<D, DeserializationError>where
Self: Sized,
D: Deserializable,
fn read<D>(&mut self) -> Result<D, DeserializationError>where
Self: Sized,
D: Deserializable,
Reads a deserializable value from
self. Read moreSource§fn read_many_iter<D>(
&mut self,
num_elements: usize,
) -> Result<ReadManyIter<'_, Self, D>, DeserializationError>where
Self: Sized,
D: Deserializable,
fn read_many_iter<D>(
&mut self,
num_elements: usize,
) -> Result<ReadManyIter<'_, Self, D>, DeserializationError>where
Self: Sized,
D: Deserializable,
Auto Trait Implementations§
impl<R> Freeze for BudgetedReader<R>where
R: Freeze,
impl<R> RefUnwindSafe for BudgetedReader<R>where
R: RefUnwindSafe,
impl<R> Send for BudgetedReader<R>where
R: Send,
impl<R> Sync for BudgetedReader<R>where
R: Sync,
impl<R> Unpin for BudgetedReader<R>where
R: Unpin,
impl<R> UnwindSafe for BudgetedReader<R>where
R: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more