rc2: macOS cross-compile fix + security/recovery hardening

- build.rs: pass target -arch to cc so macos_shim cross-compiles (x86_64-apple-darwin)
- AACS/CSS: unit-aligned decrypting sweep; per-VTS CSS title keys (hard-fail on wrong VTS);
  reject truncated Unit_Key_RO; AACS 2.0 sig-verify skip; CSS bus-auth random nonce
- recovery: gap-filling mapfile load; sweep/copy resume reconciliation; stale-mapfile abort;
  patch wedge/damage-window range reset
- mux: TS continuity + PSI CC desync guards; HEVC numTemporalLayers clamp; MPEG-2 pending
  byte-cap; PS parse_pts marker-bit validation; HdrFormat strict parse; Unknown-variant metadata
- net/keydb: network:// SSRF parity (IPv4-mapped, CGNAT, 0.0.0.0/8, Class-E); bounded keydb
  header read + size cap + error context
- io: durable mapfile fsync; NFS writeback degrade; sync_file_range error capture;
  Windows SCSI u32 transfer guard
This commit is contained in:
Matthew Jackson
2026-06-22 08:58:10 -07:00
parent 5941c059c6
commit 337e77951c
25 changed files with 1722 additions and 153 deletions
+21 -5
View File
@@ -195,8 +195,14 @@ fn bus_auth(drive: &mut Drive) -> Result<(u8, [u8; 5])> {
.map_err(|_| Error::CssAuthFailed)?;
let agid = (buf[7] >> 6) & 0x03;
// Host sends challenge
let host_challenge: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// Host sends challenge. The spec wants a fresh per-session random nonce,
// not a fixed constant — a predictable challenge weakens the bus-auth
// handshake.
let mut host_challenge = [0u8; 10];
{
use rand::RngCore;
rand::thread_rng().fill_bytes(&mut host_challenge);
}
let mut hc_buf = [0u8; 16];
hc_buf[0] = 0x00;
hc_buf[1] = 0x0E;
@@ -587,10 +593,20 @@ mod tests {
}
}
// Walk up from this file (src/css/auth.rs) to the crate `src` root.
let src_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
// Scan this crate's `src` plus the sibling workspace crates so the
// key-material logging guard covers every crate that can reach the
// CSS/AACS internals, not just libfreemkv. Missing sibling dirs (e.g.
// when building the crate standalone) are simply skipped.
let manifest = Path::new(env!("CARGO_MANIFEST_DIR"));
let workspace = manifest.parent().unwrap_or(manifest);
let mut violations = Vec::new();
scan_dir(&src_root, FORBIDDEN, &mut violations);
scan_dir(&manifest.join("src"), FORBIDDEN, &mut violations);
for sibling in ["autorip", "freemkv", "freemkv-keysources"] {
let dir = workspace.join(sibling).join("src");
if dir.is_dir() {
scan_dir(&dir, FORBIDDEN, &mut violations);
}
}
assert!(
violations.is_empty(),
"key material logged in instrumentation:\n{}",