Skip to content

Commit 66c5964

Browse files
fix(recovery): validate apply journal records (#9)
1 parent 58fee9f commit 66c5964

1 file changed

Lines changed: 33 additions & 0 deletions

File tree

src/recovery/journal.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,14 @@ pub fn decode_record(buf: &[u8]) -> Result<ApplyJournalRecord> {
174174
let action_count = u32::from_le_bytes(b4) as usize;
175175
off += 4;
176176

177+
// Every action consumes at least one kind byte plus a 16-byte segment id.
178+
// Reject hostile counts before they can drive a giant allocation.
179+
if action_count > buf.len().saturating_sub(off) / 17 {
180+
return Err(PagedbError::corruption(
181+
crate::errors::CorruptionDetail::HeaderUnverifiable,
182+
));
183+
}
184+
177185
let mut actions = Vec::with_capacity(action_count);
178186
for _ in 0..action_count {
179187
if off >= buf.len() {
@@ -215,6 +223,12 @@ pub fn decode_record(buf: &[u8]) -> Result<ApplyJournalRecord> {
215223
}
216224
}
217225

226+
if off != buf.len() {
227+
return Err(PagedbError::corruption(
228+
crate::errors::CorruptionDetail::HeaderUnverifiable,
229+
));
230+
}
231+
218232
Ok(ApplyJournalRecord {
219233
target_commit_id,
220234
actions,
@@ -401,6 +415,25 @@ mod tests {
401415
assert_eq!(decoded.actions.len(), 1);
402416
}
403417

418+
#[test]
419+
fn decode_record_rejects_trailing_bytes_inside_record() {
420+
let mut record = encode_record(&promotes(1));
421+
record.push(0xAA);
422+
423+
let err = decode_record(&record).expect_err("trailing record bytes must be corruption");
424+
assert!(matches!(err, PagedbError::Corruption(_)));
425+
}
426+
427+
#[test]
428+
fn decode_record_rejects_impossible_action_count_before_allocation() {
429+
let mut record = Vec::new();
430+
record.extend_from_slice(&42u64.to_le_bytes());
431+
record.extend_from_slice(&u32::MAX.to_le_bytes());
432+
433+
let err = decode_record(&record).expect_err("impossible action count must be corruption");
434+
assert!(matches!(err, PagedbError::Corruption(_)));
435+
}
436+
404437
async fn mk_pager() -> crate::pager::Pager<crate::vfs::memory::MemVfs> {
405438
let mk = crate::crypto::kdf::derive_mk(&[1u8; 32], &[0u8; 16], 0).unwrap();
406439
let cfg = crate::pager::PagerConfig {

0 commit comments

Comments
 (0)