Audit fixes + DVD support foundation (IFO, PS demux, MPEG-2, CSS crack)
Audit fixes (14 critical, 22 warnings): - UDF: bounds checks on all ICB/FID parsing from disc data - SCSI Linux: saturating_sub on residual, CDB length guard, buffer size guard - SCSI macOS: SCSITaskStatus u32 (was u8 — stack corruption) - AACS: EC mod_inv returns infinity instead of panic, key reduced mod n - AACS: do_handshake tries all host certs (was returning on first failure) - H.264: bounds check on SPS < 4 bytes - ContentReader: error on missing unit key (was zero-fill) - KEYDB: flat redirect loop (was recursive), 100MB response limit, Windows HOME fallback - ISO writer: AVDP extent order, partition length, allocation cap - Network: removed TCP_NODELAY on bulk stream - MKV: guard on u64::MAX seek - disc.rs: saturating_sub on extent offset, simplified dead region code - cargo fmt (610 violations), cargo clippy --fix (55 auto-fixes) DVD support (new files): - src/ifo.rs — IFO parser (VIDEO_TS.IFO, VTS_XX_0.IFO, PGC chains, cells, streams) — 13 tests - src/mux/ps.rs — MPEG-2 Program Stream demuxer (pack headers, PES, private stream 1) — 12 tests - src/mux/codec/mpeg2.rs — MPEG-2 video parser (sequence headers, I-frame detection) — 15 tests - src/css/crack.rs — split-attack algorithm (LFSR cipher needs verification — test ignored) 226 tests total (was 186), 1 ignored (CSS crack needs cipher verification).
This commit is contained in:
+199
-131
@@ -19,51 +19,52 @@
|
||||
|
||||
// ── Error codes ─────────────────────────────────────────────────────────────
|
||||
|
||||
pub const E_DEVICE_NOT_FOUND: u16 = 1000;
|
||||
pub const E_DEVICE_PERMISSION: u16 = 1001;
|
||||
pub const E_UNSUPPORTED_DRIVE: u16 = 2000;
|
||||
pub const E_PROFILE_NOT_FOUND: u16 = 2001;
|
||||
pub const E_PROFILE_PARSE: u16 = 2002;
|
||||
pub const E_UNLOCK_FAILED: u16 = 3000;
|
||||
pub const E_SIGNATURE_MISMATCH: u16 = 3001;
|
||||
pub const E_NOT_UNLOCKED: u16 = 3002;
|
||||
pub const E_NOT_CALIBRATED: u16 = 3003;
|
||||
pub const E_SCSI_ERROR: u16 = 4000;
|
||||
pub const E_SCSI_TIMEOUT: u16 = 4001;
|
||||
pub const E_IO_ERROR: u16 = 5000;
|
||||
pub const E_WRITE_ERROR: u16 = 5001;
|
||||
pub const E_DEVICE_NOT_FOUND: u16 = 1000;
|
||||
pub const E_DEVICE_PERMISSION: u16 = 1001;
|
||||
pub const E_UNSUPPORTED_DRIVE: u16 = 2000;
|
||||
pub const E_PROFILE_NOT_FOUND: u16 = 2001;
|
||||
pub const E_PROFILE_PARSE: u16 = 2002;
|
||||
pub const E_UNLOCK_FAILED: u16 = 3000;
|
||||
pub const E_SIGNATURE_MISMATCH: u16 = 3001;
|
||||
pub const E_NOT_UNLOCKED: u16 = 3002;
|
||||
pub const E_NOT_CALIBRATED: u16 = 3003;
|
||||
pub const E_SCSI_ERROR: u16 = 4000;
|
||||
pub const E_SCSI_TIMEOUT: u16 = 4001;
|
||||
pub const E_IO_ERROR: u16 = 5000;
|
||||
pub const E_WRITE_ERROR: u16 = 5001;
|
||||
// Disc format (6xxx)
|
||||
pub const E_DISC_READ: u16 = 6000;
|
||||
pub const E_MPLS_PARSE: u16 = 6001;
|
||||
pub const E_CLPI_PARSE: u16 = 6002;
|
||||
pub const E_UDF_NOT_FOUND: u16 = 6003;
|
||||
pub const E_DISC_NO_TITLES: u16 = 6004;
|
||||
pub const E_DISC_TITLE_RANGE: u16 = 6005;
|
||||
pub const E_DISC_NO_EXTENTS: u16 = 6006;
|
||||
pub const E_DISC_READ: u16 = 6000;
|
||||
pub const E_MPLS_PARSE: u16 = 6001;
|
||||
pub const E_CLPI_PARSE: u16 = 6002;
|
||||
pub const E_UDF_NOT_FOUND: u16 = 6003;
|
||||
pub const E_DISC_NO_TITLES: u16 = 6004;
|
||||
pub const E_DISC_TITLE_RANGE: u16 = 6005;
|
||||
pub const E_DISC_NO_EXTENTS: u16 = 6006;
|
||||
pub const E_IFO_PARSE: u16 = 6007;
|
||||
// AACS (7xxx)
|
||||
pub const E_AACS_NO_KEYS: u16 = 7000;
|
||||
pub const E_AACS_CERT_SHORT: u16 = 7001;
|
||||
pub const E_AACS_AGID_ALLOC: u16 = 7002;
|
||||
pub const E_AACS_CERT_REJECTED: u16 = 7003;
|
||||
pub const E_AACS_CERT_READ: u16 = 7004;
|
||||
pub const E_AACS_CERT_VERIFY: u16 = 7005;
|
||||
pub const E_AACS_KEY_READ: u16 = 7006;
|
||||
pub const E_AACS_KEY_REJECTED: u16 = 7007;
|
||||
pub const E_AACS_KEY_VERIFY: u16 = 7008;
|
||||
pub const E_AACS_VID_READ: u16 = 7009;
|
||||
pub const E_AACS_VID_MAC: u16 = 7010;
|
||||
pub const E_AACS_DATA_KEY: u16 = 7011;
|
||||
pub const E_AACS_VUK_DERIVE: u16 = 7012;
|
||||
pub const E_AACS_NO_KEYS: u16 = 7000;
|
||||
pub const E_AACS_CERT_SHORT: u16 = 7001;
|
||||
pub const E_AACS_AGID_ALLOC: u16 = 7002;
|
||||
pub const E_AACS_CERT_REJECTED: u16 = 7003;
|
||||
pub const E_AACS_CERT_READ: u16 = 7004;
|
||||
pub const E_AACS_CERT_VERIFY: u16 = 7005;
|
||||
pub const E_AACS_KEY_READ: u16 = 7006;
|
||||
pub const E_AACS_KEY_REJECTED: u16 = 7007;
|
||||
pub const E_AACS_KEY_VERIFY: u16 = 7008;
|
||||
pub const E_AACS_VID_READ: u16 = 7009;
|
||||
pub const E_AACS_VID_MAC: u16 = 7010;
|
||||
pub const E_AACS_DATA_KEY: u16 = 7011;
|
||||
pub const E_AACS_VUK_DERIVE: u16 = 7012;
|
||||
// Keydb (8xxx)
|
||||
pub const E_KEYDB_CONNECT: u16 = 8000;
|
||||
pub const E_KEYDB_HTTP: u16 = 8001;
|
||||
pub const E_KEYDB_INVALID: u16 = 8002;
|
||||
pub const E_KEYDB_WRITE: u16 = 8003;
|
||||
pub const E_KEYDB_PARSE: u16 = 8004;
|
||||
pub const E_KEYDB_LOAD: u16 = 8005;
|
||||
pub const E_KEYDB_CONNECT: u16 = 8000;
|
||||
pub const E_KEYDB_HTTP: u16 = 8001;
|
||||
pub const E_KEYDB_INVALID: u16 = 8002;
|
||||
pub const E_KEYDB_WRITE: u16 = 8003;
|
||||
pub const E_KEYDB_PARSE: u16 = 8004;
|
||||
pub const E_KEYDB_LOAD: u16 = 8005;
|
||||
// Mux (9xxx)
|
||||
pub const E_MUX_LOOKAHEAD: u16 = 9000;
|
||||
pub const E_MUX_WRITE: u16 = 9001;
|
||||
pub const E_MUX_LOOKAHEAD: u16 = 9000;
|
||||
pub const E_MUX_WRITE: u16 = 9001;
|
||||
|
||||
// ── Error enum ──────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -71,36 +72,67 @@ pub const E_MUX_WRITE: u16 = 9001;
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
// Device
|
||||
DeviceNotFound { path: String },
|
||||
DevicePermission { path: String },
|
||||
DeviceNotFound {
|
||||
path: String,
|
||||
},
|
||||
DevicePermission {
|
||||
path: String,
|
||||
},
|
||||
|
||||
// Profile
|
||||
UnsupportedDrive { vendor_id: String, product_id: String, product_revision: String },
|
||||
ProfileNotFound { vendor_id: String, product_revision: String, vendor_specific: String },
|
||||
UnsupportedDrive {
|
||||
vendor_id: String,
|
||||
product_id: String,
|
||||
product_revision: String,
|
||||
},
|
||||
ProfileNotFound {
|
||||
vendor_id: String,
|
||||
product_revision: String,
|
||||
vendor_specific: String,
|
||||
},
|
||||
ProfileParse,
|
||||
|
||||
// Unlock
|
||||
UnlockFailed,
|
||||
SignatureMismatch { expected: [u8; 4], got: [u8; 4] },
|
||||
SignatureMismatch {
|
||||
expected: [u8; 4],
|
||||
got: [u8; 4],
|
||||
},
|
||||
NotUnlocked,
|
||||
NotCalibrated,
|
||||
|
||||
// SCSI
|
||||
ScsiError { opcode: u8, status: u8, sense_key: u8 },
|
||||
ScsiTimeout { opcode: u8 },
|
||||
ScsiError {
|
||||
opcode: u8,
|
||||
status: u8,
|
||||
sense_key: u8,
|
||||
},
|
||||
ScsiTimeout {
|
||||
opcode: u8,
|
||||
},
|
||||
|
||||
// I/O
|
||||
IoError { source: std::io::Error },
|
||||
IoError {
|
||||
source: std::io::Error,
|
||||
},
|
||||
WriteError,
|
||||
|
||||
// Disc format
|
||||
DiscRead { sector: u64 },
|
||||
DiscRead {
|
||||
sector: u64,
|
||||
},
|
||||
MplsParse,
|
||||
ClpiParse,
|
||||
UdfNotFound { path: String },
|
||||
UdfNotFound {
|
||||
path: String,
|
||||
},
|
||||
DiscNoTitles,
|
||||
DiscTitleRange { index: usize, count: usize },
|
||||
DiscTitleRange {
|
||||
index: usize,
|
||||
count: usize,
|
||||
},
|
||||
DiscNoExtents,
|
||||
IfoParse,
|
||||
|
||||
// AACS
|
||||
AacsNoKeys,
|
||||
@@ -118,12 +150,20 @@ pub enum Error {
|
||||
AacsVukDerive,
|
||||
|
||||
// Keydb
|
||||
KeydbConnect { host: String },
|
||||
KeydbHttp { status: u16 },
|
||||
KeydbConnect {
|
||||
host: String,
|
||||
},
|
||||
KeydbHttp {
|
||||
status: u16,
|
||||
},
|
||||
KeydbInvalid,
|
||||
KeydbWrite { path: String },
|
||||
KeydbWrite {
|
||||
path: String,
|
||||
},
|
||||
KeydbParse,
|
||||
KeydbLoad { path: String },
|
||||
KeydbLoad {
|
||||
path: String,
|
||||
},
|
||||
|
||||
// Mux
|
||||
MuxLookahead,
|
||||
@@ -133,47 +173,48 @@ pub enum Error {
|
||||
impl Error {
|
||||
pub fn code(&self) -> u16 {
|
||||
match self {
|
||||
Error::DeviceNotFound { .. } => E_DEVICE_NOT_FOUND,
|
||||
Error::DevicePermission { .. } => E_DEVICE_PERMISSION,
|
||||
Error::UnsupportedDrive { .. } => E_UNSUPPORTED_DRIVE,
|
||||
Error::ProfileNotFound { .. } => E_PROFILE_NOT_FOUND,
|
||||
Error::ProfileParse => E_PROFILE_PARSE,
|
||||
Error::UnlockFailed => E_UNLOCK_FAILED,
|
||||
Error::DeviceNotFound { .. } => E_DEVICE_NOT_FOUND,
|
||||
Error::DevicePermission { .. } => E_DEVICE_PERMISSION,
|
||||
Error::UnsupportedDrive { .. } => E_UNSUPPORTED_DRIVE,
|
||||
Error::ProfileNotFound { .. } => E_PROFILE_NOT_FOUND,
|
||||
Error::ProfileParse => E_PROFILE_PARSE,
|
||||
Error::UnlockFailed => E_UNLOCK_FAILED,
|
||||
Error::SignatureMismatch { .. } => E_SIGNATURE_MISMATCH,
|
||||
Error::NotUnlocked => E_NOT_UNLOCKED,
|
||||
Error::NotCalibrated => E_NOT_CALIBRATED,
|
||||
Error::ScsiError { .. } => E_SCSI_ERROR,
|
||||
Error::ScsiTimeout { .. } => E_SCSI_TIMEOUT,
|
||||
Error::IoError { .. } => E_IO_ERROR,
|
||||
Error::WriteError => E_WRITE_ERROR,
|
||||
Error::DiscRead { .. } => E_DISC_READ,
|
||||
Error::MplsParse => E_MPLS_PARSE,
|
||||
Error::ClpiParse => E_CLPI_PARSE,
|
||||
Error::UdfNotFound { .. } => E_UDF_NOT_FOUND,
|
||||
Error::DiscNoTitles => E_DISC_NO_TITLES,
|
||||
Error::DiscTitleRange { .. } => E_DISC_TITLE_RANGE,
|
||||
Error::DiscNoExtents => E_DISC_NO_EXTENTS,
|
||||
Error::AacsNoKeys => E_AACS_NO_KEYS,
|
||||
Error::AacsCertShort => E_AACS_CERT_SHORT,
|
||||
Error::AacsAgidAlloc => E_AACS_AGID_ALLOC,
|
||||
Error::AacsCertRejected => E_AACS_CERT_REJECTED,
|
||||
Error::AacsCertRead => E_AACS_CERT_READ,
|
||||
Error::AacsCertVerify => E_AACS_CERT_VERIFY,
|
||||
Error::AacsKeyRead => E_AACS_KEY_READ,
|
||||
Error::AacsKeyRejected => E_AACS_KEY_REJECTED,
|
||||
Error::AacsKeyVerify => E_AACS_KEY_VERIFY,
|
||||
Error::AacsVidRead => E_AACS_VID_READ,
|
||||
Error::AacsVidMac => E_AACS_VID_MAC,
|
||||
Error::AacsDataKey => E_AACS_DATA_KEY,
|
||||
Error::AacsVukDerive => E_AACS_VUK_DERIVE,
|
||||
Error::KeydbConnect { .. } => E_KEYDB_CONNECT,
|
||||
Error::KeydbHttp { .. } => E_KEYDB_HTTP,
|
||||
Error::KeydbInvalid => E_KEYDB_INVALID,
|
||||
Error::KeydbWrite { .. } => E_KEYDB_WRITE,
|
||||
Error::KeydbParse => E_KEYDB_PARSE,
|
||||
Error::KeydbLoad { .. } => E_KEYDB_LOAD,
|
||||
Error::MuxLookahead => E_MUX_LOOKAHEAD,
|
||||
Error::MuxWrite => E_MUX_WRITE,
|
||||
Error::NotUnlocked => E_NOT_UNLOCKED,
|
||||
Error::NotCalibrated => E_NOT_CALIBRATED,
|
||||
Error::ScsiError { .. } => E_SCSI_ERROR,
|
||||
Error::ScsiTimeout { .. } => E_SCSI_TIMEOUT,
|
||||
Error::IoError { .. } => E_IO_ERROR,
|
||||
Error::WriteError => E_WRITE_ERROR,
|
||||
Error::DiscRead { .. } => E_DISC_READ,
|
||||
Error::MplsParse => E_MPLS_PARSE,
|
||||
Error::ClpiParse => E_CLPI_PARSE,
|
||||
Error::UdfNotFound { .. } => E_UDF_NOT_FOUND,
|
||||
Error::DiscNoTitles => E_DISC_NO_TITLES,
|
||||
Error::DiscTitleRange { .. } => E_DISC_TITLE_RANGE,
|
||||
Error::DiscNoExtents => E_DISC_NO_EXTENTS,
|
||||
Error::IfoParse => E_IFO_PARSE,
|
||||
Error::AacsNoKeys => E_AACS_NO_KEYS,
|
||||
Error::AacsCertShort => E_AACS_CERT_SHORT,
|
||||
Error::AacsAgidAlloc => E_AACS_AGID_ALLOC,
|
||||
Error::AacsCertRejected => E_AACS_CERT_REJECTED,
|
||||
Error::AacsCertRead => E_AACS_CERT_READ,
|
||||
Error::AacsCertVerify => E_AACS_CERT_VERIFY,
|
||||
Error::AacsKeyRead => E_AACS_KEY_READ,
|
||||
Error::AacsKeyRejected => E_AACS_KEY_REJECTED,
|
||||
Error::AacsKeyVerify => E_AACS_KEY_VERIFY,
|
||||
Error::AacsVidRead => E_AACS_VID_READ,
|
||||
Error::AacsVidMac => E_AACS_VID_MAC,
|
||||
Error::AacsDataKey => E_AACS_DATA_KEY,
|
||||
Error::AacsVukDerive => E_AACS_VUK_DERIVE,
|
||||
Error::KeydbConnect { .. } => E_KEYDB_CONNECT,
|
||||
Error::KeydbHttp { .. } => E_KEYDB_HTTP,
|
||||
Error::KeydbInvalid => E_KEYDB_INVALID,
|
||||
Error::KeydbWrite { .. } => E_KEYDB_WRITE,
|
||||
Error::KeydbParse => E_KEYDB_PARSE,
|
||||
Error::KeydbLoad { .. } => E_KEYDB_LOAD,
|
||||
Error::MuxLookahead => E_MUX_LOOKAHEAD,
|
||||
Error::MuxWrite => E_MUX_WRITE,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,41 +223,68 @@ impl Error {
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Error::DeviceNotFound { path } =>
|
||||
write!(f, "E{}: {}", self.code(), path),
|
||||
Error::DevicePermission { path } =>
|
||||
write!(f, "E{}: {}", self.code(), path),
|
||||
Error::UnsupportedDrive { vendor_id, product_id, product_revision } =>
|
||||
write!(f, "E{}: {} {} {}", self.code(),
|
||||
vendor_id.trim(), product_id.trim(), product_revision.trim()),
|
||||
Error::ProfileNotFound { vendor_id, product_revision, vendor_specific } =>
|
||||
write!(f, "E{}: {} {} {}", self.code(),
|
||||
vendor_id.trim(), product_revision.trim(), vendor_specific.trim()),
|
||||
Error::SignatureMismatch { expected, got } =>
|
||||
write!(f, "E{}: {:02x}{:02x}{:02x}{:02x}!={:02x}{:02x}{:02x}{:02x}",
|
||||
self.code(),
|
||||
expected[0], expected[1], expected[2], expected[3],
|
||||
got[0], got[1], got[2], got[3]),
|
||||
Error::ScsiError { opcode, status, sense_key } =>
|
||||
write!(f, "E{}: 0x{:02x}/0x{:02x}/0x{:02x}", self.code(), opcode, status, sense_key),
|
||||
Error::ScsiTimeout { opcode } =>
|
||||
write!(f, "E{}: 0x{:02x}", self.code(), opcode),
|
||||
Error::IoError { source } =>
|
||||
write!(f, "E{}: {}", self.code(), source),
|
||||
Error::DiscRead { sector } =>
|
||||
write!(f, "E{}: {}", self.code(), sector),
|
||||
Error::UdfNotFound { path } =>
|
||||
write!(f, "E{}: {}", self.code(), path),
|
||||
Error::DiscTitleRange { index, count } =>
|
||||
write!(f, "E{}: {}/{}", self.code(), index, count),
|
||||
Error::KeydbConnect { host } =>
|
||||
write!(f, "E{}: {}", self.code(), host),
|
||||
Error::KeydbHttp { status } =>
|
||||
write!(f, "E{}: {}", self.code(), status),
|
||||
Error::KeydbWrite { path } =>
|
||||
write!(f, "E{}: {}", self.code(), path),
|
||||
Error::KeydbLoad { path } =>
|
||||
write!(f, "E{}: {}", self.code(), path),
|
||||
Error::DeviceNotFound { path } => write!(f, "E{}: {}", self.code(), path),
|
||||
Error::DevicePermission { path } => write!(f, "E{}: {}", self.code(), path),
|
||||
Error::UnsupportedDrive {
|
||||
vendor_id,
|
||||
product_id,
|
||||
product_revision,
|
||||
} => write!(
|
||||
f,
|
||||
"E{}: {} {} {}",
|
||||
self.code(),
|
||||
vendor_id.trim(),
|
||||
product_id.trim(),
|
||||
product_revision.trim()
|
||||
),
|
||||
Error::ProfileNotFound {
|
||||
vendor_id,
|
||||
product_revision,
|
||||
vendor_specific,
|
||||
} => write!(
|
||||
f,
|
||||
"E{}: {} {} {}",
|
||||
self.code(),
|
||||
vendor_id.trim(),
|
||||
product_revision.trim(),
|
||||
vendor_specific.trim()
|
||||
),
|
||||
Error::SignatureMismatch { expected, got } => write!(
|
||||
f,
|
||||
"E{}: {:02x}{:02x}{:02x}{:02x}!={:02x}{:02x}{:02x}{:02x}",
|
||||
self.code(),
|
||||
expected[0],
|
||||
expected[1],
|
||||
expected[2],
|
||||
expected[3],
|
||||
got[0],
|
||||
got[1],
|
||||
got[2],
|
||||
got[3]
|
||||
),
|
||||
Error::ScsiError {
|
||||
opcode,
|
||||
status,
|
||||
sense_key,
|
||||
} => write!(
|
||||
f,
|
||||
"E{}: 0x{:02x}/0x{:02x}/0x{:02x}",
|
||||
self.code(),
|
||||
opcode,
|
||||
status,
|
||||
sense_key
|
||||
),
|
||||
Error::ScsiTimeout { opcode } => write!(f, "E{}: 0x{:02x}", self.code(), opcode),
|
||||
Error::IoError { source } => write!(f, "E{}: {}", self.code(), source),
|
||||
Error::DiscRead { sector } => write!(f, "E{}: {}", self.code(), sector),
|
||||
Error::UdfNotFound { path } => write!(f, "E{}: {}", self.code(), path),
|
||||
Error::DiscTitleRange { index, count } => {
|
||||
write!(f, "E{}: {}/{}", self.code(), index, count)
|
||||
}
|
||||
Error::KeydbConnect { host } => write!(f, "E{}: {}", self.code(), host),
|
||||
Error::KeydbHttp { status } => write!(f, "E{}: {}", self.code(), status),
|
||||
Error::KeydbWrite { path } => write!(f, "E{}: {}", self.code(), path),
|
||||
Error::KeydbLoad { path } => write!(f, "E{}: {}", self.code(), path),
|
||||
// Simple codes — no extra data
|
||||
_ => write!(f, "E{}", self.code()),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user