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.
3.5 KiB
AACS MKB internals — relocated rationale
Supplementary notes for src/aacs/mkb.rs comments that exceed the
comment-guard's internal-comment cap. Each section is pointed to by a
short // See docs/mkb.md — <topic> comment at the relevant call site.
Record-walker consolidation (mkb_records)
Yields (offset, rec_type, rec_len) for each record — a 4-byte header
(type byte + big-endian 24-bit length) then the body — stopping at the
00 000000 end marker or a malformed/out-of-bounds length. It is lazy
(no body clone), so a find-one-record caller never materialises the
multi-MB cvalue table. walk_mkb and every MKB record walk in
aacs::resolve/aacs::derive are built on this, so the framing rules —
and any future fix to them — live in exactly one place. They had
previously drifted across six hand-rolled copies before being
consolidated here.
cvalue record selection (mkb_find_cvalues)
The cvalue table is record type 0x05 (Media Key Data) on BOTH AACS 1.0
and AACS 2.x MKBs — its 16-byte cvalue entries are 1:1 with the 5-byte
Subset-Difference index entries in record 0x04 — the standard AACS MKB
layout.
On AACS 2.x in-drive UHD MKBs the 0x05 table is large (the full
subset-difference cvalue set: ~181k entries on a retail MKB, 1:1 with the
giant 0x04 index), while record 0x07 (Explicit Subset-Difference
Record) is a much smaller structure (~96 entries) and is NOT the cvalue
table. An earlier version of this function preferred 0x07, which
under-tested the Subset-Difference walk on UHD discs and prevented the
DK→walk path from ever finding the matching uv. The selection MUST
therefore be 0x05-first; 0x07 is only a fallback for
malformed/legacy MKBs that somehow lack a 0x05 record.
BE24 length field test (mkb_records_honors_the_high_byte_of_the_be24_length)
The record length is a big-endian 24-bit field, so the high byte
carries lengths of 64 KiB and up. The MKB records that matter most are
exactly that size — a real UHD cvalue table is 46_101 * 16 bytes and a
0x2d variant record is ~92 KiB — so a walker that dropped the high byte
would mis-frame every record of a real MKB from the first big one
onward, and every downstream key lookup would read the wrong bytes.
(The pre-existing high-byte test used total length 0x0110, whose high
byte is ZERO — it exercised the middle byte only. This test puts a
non-zero value in the high byte.)
Header-only record test (mkb_records_yields_a_header_only_record_at_the_buffer_end)
rec_len == 4 is a well-formed HEADER-ONLY record (the minimum the
walker accepts), including one sitting at the very end of the buffer
with no bytes after it. Rejecting either — the pos + 4 bound or the
rec_len < 4 floor being off by one — silently drops the MKB's last
record, and "the record isn't there" is indistinguishable from "the disc
doesn't carry it".
MKBType raw-bytes test (mkb_type_raw_reads_all_four_body_bytes)
mkb_type_raw reports the 32-bit MKBType field verbatim ([C]
§3.2.5.1.1 Table 3-2), including a value this build does not recognise —
the caller uses it to tell "unknown MKB generation" from "no Type record
at all". All four bytes must come from the record body; reading any of
them from the wrong offset yields a type that silently classifies as a
different AACS generation.
The recognised constants all share bytes with the 0x10 record-type
header byte (e.g. MKB_21_CATEGORY_C is 48 15 10 03), so this test
uses a value with four distinct bytes, none of them 0x10.