v0.11.14: audit fixes — trailing sectors, verify stop, SCSI sense, O_CLOEXEC
Fix trailing sectors dropped at extent boundaries when sector_count % 3 != 0. Add verify_title stop support via progress callback returning bool. Add O_CLOEXEC on all SCSI fd opens to prevent leak to child processes. Fix SCSI sense descriptor format detection (0x72/0x73 vs 0x70/0x71).
This commit is contained in:
+8
-3
@@ -204,13 +204,18 @@ impl DiscStream {
|
||||
let ext_sectors = self.extents[self.current_extent].sector_count;
|
||||
|
||||
let remaining = ext_sectors.saturating_sub(self.current_offset);
|
||||
let sectors = remaining.min(self.batch_sectors as u32) as u16;
|
||||
let sectors = sectors - (sectors % 3);
|
||||
if sectors == 0 {
|
||||
if remaining == 0 {
|
||||
self.current_extent += 1;
|
||||
self.current_offset = 0;
|
||||
return self.fill_extents();
|
||||
}
|
||||
let mut sectors = remaining.min(self.batch_sectors as u32) as u16;
|
||||
// Align to 3-sector AACS units when possible, but never drop
|
||||
// trailing sectors at extent boundaries. decrypt_sectors() safely
|
||||
// skips partial units (chunks shorter than ALIGNED_UNIT_LEN).
|
||||
if sectors >= 3 {
|
||||
sectors -= sectors % 3;
|
||||
}
|
||||
|
||||
let lba = ext_start + self.current_offset;
|
||||
let bytes = sectors as usize * 2048;
|
||||
|
||||
+13
-6
@@ -68,7 +68,7 @@ impl SgIoTransport {
|
||||
let fd = unsafe {
|
||||
libc::open(
|
||||
c_path.as_ptr() as *const libc::c_char,
|
||||
libc::O_RDWR | libc::O_NONBLOCK,
|
||||
libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC,
|
||||
)
|
||||
};
|
||||
if fd < 0 {
|
||||
@@ -126,7 +126,7 @@ impl SgIoTransport {
|
||||
let probe_fd = unsafe {
|
||||
libc::open(
|
||||
c_path.as_ptr() as *const libc::c_char,
|
||||
libc::O_RDWR | libc::O_NONBLOCK,
|
||||
libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC,
|
||||
)
|
||||
};
|
||||
if probe_fd >= 0 {
|
||||
@@ -140,7 +140,7 @@ impl SgIoTransport {
|
||||
let fd = unsafe {
|
||||
libc::open(
|
||||
c_path.as_ptr() as *const libc::c_char,
|
||||
libc::O_RDWR | libc::O_NONBLOCK,
|
||||
libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC,
|
||||
)
|
||||
};
|
||||
if fd < 0 {
|
||||
@@ -373,7 +373,7 @@ impl ScsiTransport for SgIoTransport {
|
||||
let new_fd = unsafe {
|
||||
libc::open(
|
||||
c_path.as_ptr() as *const libc::c_char,
|
||||
libc::O_RDWR | libc::O_NONBLOCK,
|
||||
libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC,
|
||||
)
|
||||
};
|
||||
self.fd = if new_fd >= 0 { new_fd } else { -1 };
|
||||
@@ -402,8 +402,15 @@ impl ScsiTransport for SgIoTransport {
|
||||
let bytes_transferred = (data.len() as i32).saturating_sub(hdr.resid).max(0) as usize;
|
||||
|
||||
if hdr.status != 0 {
|
||||
let sense_key = if hdr.sb_len_wr > 2 {
|
||||
sense[2] & 0x0F
|
||||
let sense_key = if hdr.sb_len_wr >= 3 {
|
||||
let response_code = sense[0] & 0x7F;
|
||||
if response_code == 0x72 || response_code == 0x73 {
|
||||
// Descriptor format sense: sense key at byte 1
|
||||
sense[1] & 0x0F
|
||||
} else {
|
||||
// Fixed format sense (0x70/0x71): sense key at byte 2
|
||||
sense[2] & 0x0F
|
||||
}
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
+13
-4
@@ -73,10 +73,12 @@ impl VerifyResult {
|
||||
}
|
||||
|
||||
/// Progress callback: (sectors_done, total_sectors, current_status)
|
||||
pub type ProgressFn = Box<dyn FnMut(u64, u64, SectorStatus)>;
|
||||
/// Return false to stop verification early.
|
||||
pub type ProgressFn = Box<dyn FnMut(u64, u64, SectorStatus) -> bool>;
|
||||
|
||||
/// Verify all sectors in a title's extents.
|
||||
/// Reads in batches for speed, falls back to single-sector on failure.
|
||||
/// The progress callback returns false to request early stop.
|
||||
pub fn verify_title(
|
||||
reader: &mut dyn SectorReader,
|
||||
title: &DiscTitle,
|
||||
@@ -90,12 +92,13 @@ pub fn verify_title(
|
||||
let mut bad: u64 = 0;
|
||||
let mut ranges: Vec<SectorRange> = Vec::new();
|
||||
let mut sectors_done: u64 = 0;
|
||||
let mut _stopped = false;
|
||||
let mut byte_offset: u64 = 0;
|
||||
|
||||
let total_sectors: u64 = title.extents.iter().map(|e| e.sector_count as u64).sum();
|
||||
let mut buf = vec![0u8; batch_sectors as usize * 2048];
|
||||
|
||||
for ext in &title.extents {
|
||||
'outer: for ext in &title.extents {
|
||||
let mut offset: u32 = 0;
|
||||
while offset < ext.sector_count {
|
||||
let remaining = ext.sector_count - offset;
|
||||
@@ -133,7 +136,10 @@ pub fn verify_title(
|
||||
|
||||
sectors_done += count as u64;
|
||||
if let Some(ref mut cb) = on_progress {
|
||||
cb(sectors_done, total_sectors, status);
|
||||
if !cb(sectors_done, total_sectors, status) {
|
||||
_stopped = true;
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Batch failed — test each sector individually
|
||||
@@ -196,7 +202,10 @@ pub fn verify_title(
|
||||
|
||||
sectors_done += 1;
|
||||
if let Some(ref mut cb) = on_progress {
|
||||
cb(sectors_done, total_sectors, status);
|
||||
if !cb(sectors_done, total_sectors, status) {
|
||||
_stopped = true;
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user