mirror of
https://github.com/freemkv/libfreemkv.git
synced 2026-10-07 18:13:10 +00:00
dirimage: refuse a read that begins past the image's capacity
read_sectors fabricated zeros and reported success for any LBA, including one at or beyond the image's own capacity — an oversized/crafted offset that a real file/ISO source rejects. Refuse a read whose START is past capacity (as read_exact does past EOF) while still zero-padding a batch that starts in range and overshoots the end, which the mux's final batch and the FS scan's fixed-LBA probes rely on. Split the read-range test to pin both behaviours.
This commit is contained in:
@@ -259,6 +259,19 @@ impl SectorSource for DirImage {
|
|||||||
if buf.len() < need {
|
if buf.len() < need {
|
||||||
return Err(Error::UdfBufferTooSmall);
|
return Err(Error::UdfBufferTooSmall);
|
||||||
}
|
}
|
||||||
|
// A read that BEGINS at or beyond the image's own capacity addresses a
|
||||||
|
// sector that cannot exist (an oversized/crafted offset): refuse it, as a
|
||||||
|
// real file/ISO source's read_exact does past EOF, rather than fabricate
|
||||||
|
// zeros and report success. A batch that starts IN range and overshoots
|
||||||
|
// the end is still fine — its tail past capacity zero-pads below, which
|
||||||
|
// the mux's final batch and the FS scan's fixed-LBA probes both expect.
|
||||||
|
if count > 0 && lba >= self.total_sectors {
|
||||||
|
return Err(Error::DiscRead {
|
||||||
|
sector: lba as u64,
|
||||||
|
status: None,
|
||||||
|
sense: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
buf[..need].fill(0);
|
buf[..need].fill(0);
|
||||||
// Walk the request in RUNS, not sector by sector: a mux batch (8192
|
// Walk the request in RUNS, not sector by sector: a mux batch (8192
|
||||||
// sectors) almost always lands in one extent, so per-sector seek+read
|
// sectors) almost always lands in one extent, so per-sector seek+read
|
||||||
|
|||||||
+25
-7
@@ -203,18 +203,36 @@ fn a_file_past_the_ad_ceiling_reads_back_as_multiple_extents() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads outside any planned extent are zeros, not errors — a real image has
|
/// An IN-RANGE gap (a sector below capacity that no extent covers) reads as
|
||||||
/// unrecorded sectors too, and `read_filesystem` probes fixed LBAs (256, the
|
/// zeros, not an error — a real image has unrecorded sectors too, and
|
||||||
/// VDS window) before it knows what is there.
|
/// `read_filesystem` probes fixed LBAs (256, the VDS window) before it knows
|
||||||
|
/// what is there. But a read AT OR BEYOND the image's own capacity is out of
|
||||||
|
/// range: a real file/ISO source errors there, so DirImage must too rather than
|
||||||
|
/// fabricate zeros and let an oversized offset fill an output with nothing.
|
||||||
#[test]
|
#[test]
|
||||||
fn gaps_and_out_of_range_reads_are_zero_filled() {
|
fn an_in_range_gap_reads_zeros_but_a_past_capacity_read_errors() {
|
||||||
let (s, _, _) = bdmv_scratch();
|
let (s, _, _) = bdmv_scratch();
|
||||||
let mut img = DirImage::open(s.path()).unwrap();
|
let mut img = DirImage::open(s.path()).unwrap();
|
||||||
let cap = img.capacity_sectors();
|
let cap = img.capacity_sectors();
|
||||||
|
|
||||||
|
// In-range gap: sector 200 sits below the data floor and covers no file.
|
||||||
|
let mut buf = [0xAAu8; SECTOR];
|
||||||
|
let n = img.read_sectors(200, 1, &mut buf, false).unwrap();
|
||||||
|
assert_eq!(n, SECTOR);
|
||||||
|
assert!(buf.iter().all(|&b| b == 0), "an in-range gap reads as zeros");
|
||||||
|
|
||||||
|
// A read that BEGINS past the image's capacity is refused, not zero-filled.
|
||||||
let mut buf = [0xAAu8; SECTOR * 2];
|
let mut buf = [0xAAu8; SECTOR * 2];
|
||||||
let n = img.read_sectors(cap + 10, 2, &mut buf, false).unwrap();
|
assert!(
|
||||||
assert_eq!(n, SECTOR * 2);
|
img.read_sectors(cap + 10, 2, &mut buf, false).is_err(),
|
||||||
assert!(buf.iter().all(|&b| b == 0));
|
"a read that begins past capacity must be refused, not fabricated"
|
||||||
|
);
|
||||||
|
|
||||||
|
// A read that STARTS in range but overshoots the end still succeeds, tail
|
||||||
|
// zero-padded — the mux's final batch and the FS scan both rely on that.
|
||||||
|
let mut buf = vec![0xAAu8; SECTOR * 4];
|
||||||
|
let n = img.read_sectors(cap - 1, 4, &mut buf, false).unwrap();
|
||||||
|
assert_eq!(n, SECTOR * 4, "an in-range start may overshoot and zero-pad");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Two runs over the same unchanged folder must produce the same image, byte
|
/// Two runs over the same unchanged folder must produce the same image, byte
|
||||||
|
|||||||
Reference in New Issue
Block a user