Skip to content
Merged
Show file tree
Hide file tree
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
18 changes: 18 additions & 0 deletions crates/ember-persistence/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,24 @@ pub const MAX_PERSISTED_VECTOR_DIMS: u32 = 65_536;
/// Prevents corrupt count fields from causing unbounded loops.
pub const MAX_PERSISTED_VECTOR_COUNT: u32 = 10_000_000;

/// Maximum total f32 elements (dim * count) for vector deserialization.
/// Caps total allocation at ~4 GB. Without this, a crafted file with
/// 65536 dims x 10M vectors would attempt ~2.6 TB.
pub const MAX_PERSISTED_VECTOR_TOTAL_FLOATS: u64 = 1_000_000_000;

/// Validates that the total vector element budget (dim * count) is within
/// bounds. Call after validating dim and count individually.
pub fn validate_vector_total(dim: u32, count: u32) -> Result<(), FormatError> {
let total = dim as u64 * count as u64;
if total > MAX_PERSISTED_VECTOR_TOTAL_FLOATS {
return Err(FormatError::InvalidData(format!(
"vector total elements ({dim} dims x {count} vectors = {total}) \
exceeds max {MAX_PERSISTED_VECTOR_TOTAL_FLOATS}"
)));
}
Ok(())
}

/// Verifies that two CRC32 values match.
pub fn verify_crc32_values(computed: u32, stored: u32) -> Result<(), FormatError> {
if computed != stored {
Expand Down
2 changes: 2 additions & 0 deletions crates/ember-persistence/src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ fn parse_snap_value(r: &mut impl io::Read) -> Result<SnapValue, FormatError> {
format::MAX_PERSISTED_VECTOR_COUNT
)));
}
format::validate_vector_total(dim, count)?;
let mut elements = Vec::with_capacity(format::capped_capacity(count));
for _ in 0..count {
let name = read_snap_string(r, "vector element name")?;
Expand Down Expand Up @@ -683,6 +684,7 @@ impl SnapshotReader {
format::MAX_PERSISTED_VECTOR_COUNT
)));
}
format::validate_vector_total(dim, count)?;
format::write_u32(&mut buf, count)?;
let mut elements = Vec::with_capacity(format::capped_capacity(count));
for _ in 0..count {
Expand Down
Loading