Files
libfreemkv/docs/inf.md
T
Matthew Jackson 6e14fc0c0c libfreemkv: 1.7.0 groundwork — sector-recycle soundness + CI hardening
Security
- Remove the unsafe Vec::set_len over recycled sector buffers — UB reachable
  from safe code (GHSA-j8ww-f5fg-9pmh, low). Uses Vec::resize; pooling unchanged.

CI / tooling
- clippy on stable with the MSRV single-sourced from Cargo.toml; cargo-deny
  dependency-audit gate with first-party git sources allowed (#15); audience-based
  comment-guard (#17).

Docs
- README (keydb ownership, BD-J parser count), drive-access transport/reset
  notes, mux timeline module-doc links.
2026-09-02 12:40:55 -07:00

4.7 KiB
Raw Blame History

aacs::inf — notes

UnitKeyFile's hand-written Debug

Redacting Debug, per the policy aacs::types documents: this struct holds the disc's ENCRYPTED CPS unit keys — exactly the material a keydb entry stores — plus the disc hash they are looked up by. A derived Debug printed every key byte verbatim, so any {:?} (a downstream crate, an assert_eq! failure message, a future tracing::debug! in this module) leaked them. Only non-secret shape is printed. Guarded by unit_key_file_debug_is_redacted.

The disc hash is the public keydb lookup key, printed as hex the same way DiscEntry prints its own — never as raw bytes.

parse_vtkf

Layout — AACS "HD DVD and DVD Pre-recorded Book" Table 3-8, a fixed 2480-byte file, verified byte-exact against real discs (Freedom VTKF090, Dukes of Hazzard VTKF000):

  [0x00..0x0C] magic "DVD_HD_V_TKF"
  [0x0C..0x10] BE32 HD_VTKF_SIZE (2480)
  [0x10..0x1C] associated playlist name ("VPLST%%%.XPL")
  [0x1C..0x80] reserved
  [0x80..]     64 entries × 36 bytes:
                 BIFO (1) | reserved (3) | ENCRYPTED title key (16) | binding MAC (16)
                 BIFO bit 7 (AV_FLG) set = this slot holds a title key
                 (pre-recorded discs fill the binding MAC with 0xFF)
  [0x9A0..2480] 16-byte TKF MAC (CMAC keyed by Kvu — NOT a key)

The slot index (1-based) is the CPS unit number, so an absent slot is SKIPPED (not a terminator) — collapsing gaps would renumber later keys and hand the wrong title key to CPS unit N+1. The title→CPS mapping is playlist-driven (VPLST%%%.XPL) and owned by the HD DVD enumerator, so title_cps_unit is left empty here.

The prior parser used a 32-byte stride (a 12-byte pad instead of the 16-byte binding MAC). That reads entry #1 correctly but drifts +4 bytes per entry after it, so it only decrypted single-CPS-unit discs; every multi-key VTKF (real multi-CPS-unit HD-DVD titles) yielded garbage keys for CPS unit ≥2.

synth_vtkf test helper

Build a synthetic VTKF%%%.AACS matching the real on-disc layout (AACS HD DVD Book Table 3-8, verified against Freedom VTKF090 and Dukes VTKF000): magic, BE32 size, playlist name, reserved to 0x80, then 64 entry slots of 36 bytes (the first keys.len() present with AV_FLG set, the rest empty), a reserved gap, and the 16-byte trailing TKF MAC.

unit_key_file_debug_is_redacted test

UnitKeyFile holds the disc's ENCRYPTED CPS unit keys. A derived Debug printed every byte; the hand-written impl must not. Sentinel key byte 0xD5 = decimal 213 (a derived Debug renders [u8; 16] in decimal), the same probe aacs::types::redaction_tests uses. Mutation guard: putting #[derive(Debug)] back fails this.

read_mkb_from_drive_returns_the_concatenated_pack_payload test

read_mkb_from_drive is the in-drive MKB source: every AACS derivation downstream (mkb_find_mk_dv, the subset-difference walk, the whole Media Key ladder) consumes exactly what it returns. An empty return is not a benign "no MKB" — it is a total read failure reported as success, and every derivation then fails with a key-not-found code that points the operator at their keydb rather than at the drive.

This pins the CONTENT: the concatenated payload of all packs, in pack order, byte for byte.

read_mkb_from_drive_issues_the_exact_mmc_cdb_for_each_pack test

The CDB is what the drive actually acts on, and every byte of it is load-bearing: a wrong format code returns a different disc structure entirely, and a wrong allocation length truncates the pack. The existing test above pins the opcode, the format code and the pack number; this pins the WHOLE 12-byte CDB, so no field can drift unnoticed.

Expected layout (MMC-6 READ DISC STRUCTURE, AACS MKB format): [0] opcode, [1] media type 0x01, [2..6] address = pack number (BE32), [6] layer 0, [7] format 0x83, [8..10] allocation length BE16 = 32772 = 0x80 0x04, [10..12] reserved/control.

read_mkb_from_drive_accepts_a_full_size_pack test

A pack payload filling the FULL 32768-byte window must come back whole. The len > 0 && len <= 32768 bound is what stands between a maximal pack and a silently dropped one, and the small payloads used elsewhere in this module never reach it.

read_mkb_from_drive_ignores_a_pack_declaring_more_than_the_buffer_holds test

A drive that DECLARES more payload than it returned must not be believed. The BE16 length in the response header is drive-supplied data: a firmware bug, a short transfer, or a hostile device can put a value in it that runs past the 32772-byte buffer. Copying len bytes on that word alone panics the rip thread mid-scan.

Both the first-pack read and the per-pack loop carry the same bound, so both are exercised here: the over-declared pack contributes nothing and the honest pack still comes through.