Skip to content

Commit c4f4acb

Browse files
authored
fix: make sure bitfield is within limits (#535)
Error if one tries to decode a bitfield that is too large.
1 parent 26c6f4c commit c4f4acb

File tree

4 files changed

+79
-9
lines changed

4 files changed

+79
-9
lines changed

ipld/bitfield/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ pub use rleplus::Error;
2121
use thiserror::Error;
2222
pub use unvalidated::{UnvalidatedBitField, Validate};
2323

24+
/// MaxEncodedSize is the maximum encoded size of a bitfield. When expanded into
25+
/// a slice of runs, a bitfield of this size should not exceed 2MiB of memory.
26+
///
27+
/// This bitfield can fit at least 3072 sparse elements.
28+
pub(crate) const MAX_ENCODED_SIZE: usize = 32 << 10;
29+
2430
#[derive(Clone, Error, Debug)]
2531
#[error("bitfields may not include u64::MAX")]
2632
pub struct OutOfRangeError;

ipld/bitfield/src/rleplus/mod.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
7575
pub use writer::BitWriter;
7676

7777
use super::BitField;
78-
use crate::RangeSize;
79-
80-
// MaxEncodedSize is the maximum encoded size of a bitfield. When expanded into
81-
// a slice of runs, a bitfield of this size should not exceed 2MiB of memory.
82-
//
83-
// This bitfield can fit at least 3072 sparse elements.
84-
const MAX_ENCODED_SIZE: usize = 32 << 10;
78+
use crate::{RangeSize, MAX_ENCODED_SIZE};
8579

8680
impl Serialize for BitField {
8781
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>

ipld/bitfield/src/unvalidated.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use fvm_ipld_encoding::serde_bytes;
77
use serde::{Deserialize, Deserializer, Serialize};
88

99
use super::BitField;
10-
use crate::Error;
10+
use crate::{Error, MAX_ENCODED_SIZE};
1111

1212
/// A trait for types that can produce a `&BitField` (or fail to do so).
1313
/// Generalizes over `&BitField` and `&mut UnvalidatedBitField`.
@@ -77,6 +77,12 @@ impl<'de> Deserialize<'de> for UnvalidatedBitField {
7777
D: Deserializer<'de>,
7878
{
7979
let bytes: Vec<u8> = serde_bytes::deserialize(deserializer)?;
80+
if bytes.len() > MAX_ENCODED_SIZE {
81+
return Err(serde::de::Error::custom(format!(
82+
"encoded bitfield was too large {}",
83+
bytes.len()
84+
)));
85+
}
8086
Ok(Self::Unvalidated(bytes))
8187
}
8288
}

ipld/bitfield/tests/bitfield_tests.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use std::collections::HashSet;
55

6-
use fvm_ipld_bitfield::{bitfield, BitField};
6+
use fvm_ipld_bitfield::{bitfield, BitField, UnvalidatedBitField};
77
use rand::{Rng, SeedableRng};
88
use rand_xorshift::XorShiftRng;
99

@@ -232,3 +232,67 @@ fn exceeds_bitfield_range() {
232232
BitField::try_from_bits([0, 1, 4, 99, u64::MAX - 1])
233233
.expect("expected setting u64::MAX-1 to succeed");
234234
}
235+
236+
#[test]
237+
fn bitfield_custom() {
238+
let mut bf = BitField::new();
239+
240+
// Set alternating bits for worst-case size performance
241+
let mut i = 0;
242+
while i < 1_000_000 {
243+
bf.set(i);
244+
i += 2;
245+
}
246+
println!("# Set bits: {}", bf.len());
247+
248+
// Standard serialization catches MAX_ENCODING_SIZE issues
249+
println!("Attempting to serialize...");
250+
match fvm_ipld_encoding::to_vec(&bf) {
251+
Ok(_) => panic!("This should have failed!"),
252+
Err(_) => println!("Standard serialization failed, as expected"),
253+
}
254+
255+
// Bypass to_vec enc size check so we can test deserialization
256+
println!("Manually serializing...");
257+
// CBOR prefix for the bytes
258+
let mut cbor = vec![0x5A, 0x00, 0x01, 0xE8, 0x49];
259+
cbor.extend_from_slice(&bf.to_bytes());
260+
println!("Success!");
261+
262+
println!("# bytes of cbor: {}", cbor.len());
263+
println!("Header: {:#010b}", cbor[0]);
264+
println!("-- maj type {}", (cbor[0] & 0xe0) >> 5);
265+
266+
// Get size of payload size
267+
let info = cbor[0] & 0x1f;
268+
println!("-- adtl info {}", info);
269+
270+
// Get payload size
271+
let size = match info {
272+
0..=23 => info as usize,
273+
24 => cbor[1] as usize,
274+
25 => u16::from_be_bytes([cbor[1], cbor[2]]) as usize,
275+
26 => u32::from_be_bytes([cbor[1], cbor[2], cbor[3], cbor[4]]) as usize,
276+
27 => u64::from_be_bytes([
277+
cbor[1], cbor[2], cbor[3], cbor[4], cbor[5], cbor[6], cbor[7], cbor[8],
278+
]) as usize,
279+
_ => {
280+
println!("OUT OF RANGE");
281+
0
282+
}
283+
};
284+
285+
println!("{} byte payload", size);
286+
287+
// Deserialize and validate malicious payload
288+
println!("Attempting to deserialize and validate...");
289+
match fvm_ipld_encoding::from_slice::<UnvalidatedBitField>(&cbor) {
290+
Ok(mut bitfield) => {
291+
bitfield.validate_mut().unwrap();
292+
panic!("Error - deserialized/validated payload over 32768 bytes.");
293+
}
294+
Err(_) => {
295+
println!("Success - payload over 32768 bytes cannot be deserialized");
296+
}
297+
}
298+
}

0 commit comments

Comments
 (0)