Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix value explosion in arbitrary fuzzer #485

Merged
merged 2 commits into from
Aug 23, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 67 additions & 22 deletions fuzz/fuzz_targets/bench/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub fn roundtrip_arbitrary_typed_ron_or_panic(data: &[u8]) -> Option<TypedSerdeD
// Everything else is actually a bug we want to find
Err(err) => panic!("{:?} -! {:?}", typed_value, err),
};

if let Err(err) = ron::Options::default().from_str::<ron::Value>(&ron) {
match err.code {
// Erroring on deep recursion is better than crashing on a stack overflow
Expand All @@ -38,6 +39,7 @@ pub fn roundtrip_arbitrary_typed_ron_or_panic(data: &[u8]) -> Option<TypedSerdeD
_ => panic!("{:?} -> {} -! {:?}", typed_value, ron, err),
}
};

if let Err(err) = ron::Options::default().from_str_seed(&ron, &typed_value) {
match err.code {
// Erroring on deep recursion is better than crashing on a stack overflow
Expand All @@ -46,7 +48,7 @@ pub fn roundtrip_arbitrary_typed_ron_or_panic(data: &[u8]) -> Option<TypedSerdeD
_ => panic!("{:?} -> {} -! {:?}", typed_value, ron, err),
}
};
// TODO: also do typed deserialise

Some(typed_value)
} else {
None
Expand Down Expand Up @@ -189,7 +191,12 @@ impl<'a> Serialize for BorrowedTypedSerdeData<'a> {
serializer.serialize_none()
}
}
(SerdeDataType::Array { kind, len }, SerdeDataValue::Seq { elems }) => {
(
SerdeDataType::Array {
kind_len: (kind, len),
},
SerdeDataValue::Seq { elems },
) => {
if elems.len() != *len {
return Err(serde::ser::Error::custom("mismatch array len"));
}
Expand Down Expand Up @@ -530,7 +537,12 @@ impl<'a, 'de> DeserializeSeed<'de> for BorrowedTypedSerdeData<'a> {
value: value.as_deref(),
})
}
(SerdeDataType::Array { kind, len }, SerdeDataValue::Seq { elems }) => {
(
SerdeDataType::Array {
kind_len: (kind, len),
},
SerdeDataValue::Seq { elems },
) => {
struct ArrayVisitor<'a> {
kind: &'a SerdeDataType<'a>,
elems: &'a [SerdeDataValue<'a>],
Expand Down Expand Up @@ -1327,10 +1339,8 @@ pub enum SerdeDataType<'a> {
inner: Box<Self>,
},
Array {
#[arbitrary(with = arbitrary_recursion_guard)]
kind: Box<Self>,
#[arbitrary(with = arbitrary_recursion_guard)]
len: usize,
#[arbitrary(with = arbitrary_array_len_recursion_guard)]
kind_len: (Box<Self>, usize),
},
Tuple {
#[arbitrary(with = arbitrary_recursion_guard)]
Expand Down Expand Up @@ -1403,11 +1413,9 @@ impl<'a> SerdeDataType<'a> {
};
Ok(SerdeDataValue::Option { inner: value })
}
SerdeDataType::Array { kind, len } => {
if *len > 32 {
// Restrict array lengths to be reasonable, as arbitrary cannot
return Err(arbitrary::Error::IncorrectFormat);
}
SerdeDataType::Array {
kind_len: (kind, len),
} => {
let mut array = Vec::with_capacity(*len);
for _ in 0..*len {
array.push(kind.arbitrary_value(u)?);
Expand All @@ -1422,17 +1430,15 @@ impl<'a> SerdeDataType<'a> {
Ok(SerdeDataValue::Seq { elems: tuple })
}
SerdeDataType::Vec { item } => {
let len = u.arbitrary_len::<SerdeDataValue>()?.min(4);
let mut vec = Vec::with_capacity(len);
for _ in 0..len {
let mut vec = Vec::new();
while u.arbitrary()? {
vec.push(item.arbitrary_value(u)?);
}
Ok(SerdeDataValue::Seq { elems: vec })
}
SerdeDataType::Map { key, value } => {
let len = u.arbitrary_len::<SerdeDataValue>()?.min(4);
let mut map = Vec::with_capacity(len);
for _ in 0..len {
let mut map = Vec::new();
while u.arbitrary()? {
map.push((key.arbitrary_value(u)?, value.arbitrary_value(u)?));
}
Ok(SerdeDataValue::Map { elems: map })
Expand Down Expand Up @@ -1559,6 +1565,46 @@ fn arbitrary_recursion_guard<'a, T: Arbitrary<'a> + Default>(
result
}

fn arbitrary_array_len_recursion_guard<'a>(
u: &mut Unstructured<'a>,
) -> arbitrary::Result<(Box<SerdeDataType<'a>>, usize)> {
const MAX_ARRAY_SPREAD: usize = 32;
static ARRAY_SPREAD: AtomicUsize = AtomicUsize::new(1);

let max_depth = ron::Options::default()
.recursion_limit
.map_or(256, |limit| limit * 2);

// Fall back to zero-sized arrays if the input is exhausted
if u.is_empty() {
return Ok((Box::new(SerdeDataType::Unit), 0));
}

let result = if RECURSION_DEPTH.fetch_add(1, Ordering::Relaxed) < max_depth {
// Limit the maximum array spread, since arbitrary cannot
let spread = ARRAY_SPREAD.load(Ordering::Relaxed);
let len = u.int_in_range::<usize>(0..=(MAX_ARRAY_SPREAD / spread).clamp(1, 16))?;

// Only generate intricate inner array types if the length is non-zero
let kind = if len > 0 {
ARRAY_SPREAD.swap(spread * len, Ordering::Relaxed);
let kind = SerdeDataType::arbitrary(u)?;
ARRAY_SPREAD.swap(spread, Ordering::Relaxed);
kind
} else {
SerdeDataType::Unit
};

Ok((Box::new(kind), len))
} else {
Ok((Box::new(SerdeDataType::Unit), 0))
};

RECURSION_DEPTH.fetch_sub(1, Ordering::Relaxed);

result
}

fn arbitrary_str_tuple_vec_recursion_guard<'a, T: Arbitrary<'a>>(
u: &mut Unstructured<'a>,
) -> arbitrary::Result<(Vec<&'a str>, Vec<T>)> {
Expand All @@ -1567,11 +1613,10 @@ fn arbitrary_str_tuple_vec_recursion_guard<'a, T: Arbitrary<'a>>(
.map_or(256, |limit| limit * 2);

let result = if RECURSION_DEPTH.fetch_add(1, Ordering::Relaxed) < max_depth {
let len = u.arbitrary_len::<(&str, T)>()?;
let mut s = Vec::with_capacity(len);
let mut v = Vec::with_capacity(len);
let mut s = Vec::new();
let mut v = Vec::new();

for _ in 0..len {
while u.arbitrary()? {
s.push(<&str>::arbitrary(u)?);
v.push(T::arbitrary(u)?);
}
Expand Down
Loading