fix: assorted correctness fixes and dead-code cleanup

- aacs/resolve: a media-keys-only provider missing the VID classifies as
  VidUnavailable, not NoMaterial (an MK derives the VUK once the VID
  arrives).
- disc/bluray: mark a clip seen only after its .clpi parses, so a
  transient parse failure on the first PlayItem cannot suppress the
  clip's extents for a later PlayItem referencing it that succeeds.
- disc/patch: log rather than swallow mapfile record/flush failures on a
  reverify downgrade, so a failed persist cannot silently mismark a bad
  unit good on resume.
- mux/ts: flag a discontinuity when a partial PES is dropped, matching
  the other partial-drop paths.
- mux/demux_thread: the no-demuxer branch forwards an empty batch for
  early consumer-disconnect detection instead of reading the whole disc.
- io/pipeline: correct the send-timing log (as_secs_f64, not as_micros
  printed as ms).
- aacs/derive, aacs/variant, disc/read_error, keysource: comment/doc
  accuracy. sector/prefetched, udf: remove dead fields/functions.
- mux/disc: assert unit-aligned read counts in the test.
This commit is contained in:
Matthew Jackson
2026-07-08 14:44:15 -07:00
parent 67aba17173
commit 0d587d1154
13 changed files with 95 additions and 114 deletions
+8 -7
View File
@@ -203,13 +203,14 @@ pub fn derive_media_key_and_pk_from_dk(
let p_uv = &uvs[1 + 5 * uvs_idx..];
let u_mask_shift = uvs[5 * uvs_idx]; // byte before the UV value
if u_mask_shift & 0xC0 != 0 {
break; // device revoked
}
// Shifts of 32..=63 (0x20..=0x3F pass the 0xC0 mask above) would
// panic in debug / wrap to a wrong mask in release. The MKB byte
// is disc-controlled, so a crafted/corrupt MKB must not crash the
// ripper: skip an out-of-range slot rather than `<<` it.
// `num_uvs` was computed via `take_while(.. c[0] & 0xC0 == 0)`, so
// every iterated slot already has its revoked-marker bits clear — no
// inner `& 0xC0` re-check is needed (it would be unreachable).
//
// Shifts of 32..=63 (0x20..=0x3F) have those bits clear but would
// panic in debug / wrap to a wrong mask in release. The MKB byte is
// disc-controlled, so a crafted/corrupt MKB must not crash the ripper:
// skip an out-of-range slot rather than `<<` it.
if u_mask_shift >= 32 {
continue;
}
+6 -2
View File
@@ -106,8 +106,12 @@ pub fn resolve_keys_with_reason(
pub(crate) fn classify_resolve_failure(ctx: &ResolveContext<'_>) -> ResolveFailure {
let has_vid = *ctx.volume_id != [0u8; 16];
let providers = super::provider::Providers(ctx.providers);
let has_derivation_material =
!providers.device_keys().is_empty() || !providers.processing_keys().is_empty();
// Media keys are also derivation material: with an MK you can derive the VUK
// once you have the VID, so a media-keys-only provider that is merely missing
// the VID is VidUnavailable, not NoMaterial.
let has_derivation_material = !providers.device_keys().is_empty()
|| !providers.processing_keys().is_empty()
|| !providers.media_keys().is_empty();
if !has_vid && has_derivation_material {
ResolveFailure::VidUnavailable
} else {
+5 -8
View File
@@ -201,14 +201,11 @@ pub fn walk_processing_key(
// parse stops, no inner re-check needed.
let u_mask_shift = uvs[5 * uvs_idx];
if u_mask_shift & 0xC0 != 0 {
break;
}
// 0x20..=0x3F (32..=63) pass the 0xC0 revoked-marker check but are
// out of range for a u32 shift. `wrapping_shl` would silently
// compute shift % 32 (e.g. 32 → no shift → 0xFFFF_FFFF), matching a
// wrong uv slot and deriving a wrong key. Disc-controlled byte:
// skip the slot instead.
// 0x20..=0x3F (32..=63) have their revoked-marker bits clear (so they
// pass the take_while above) but are out of range for a u32 shift.
// `wrapping_shl` would silently compute shift % 32 (e.g. 32 → no shift
// → 0xFFFF_FFFF), matching a wrong uv slot and deriving a wrong key.
// Disc-controlled byte: skip the slot instead.
if u_mask_shift >= 32 {
continue;
}