Round 4: fix 26 defects across crypto, resource use and codec paths

Twenty-six confirmed findings from the fourth audit round, landed as one
cluster because they were found by agents working over disjoint file sets.

The one worth calling out is a pair of AACS tests that could not fail.
Both asserted CBC behaviour against a hand-rolled expectation that
happened to be IV-independent, so replacing AACS_IV with sixteen zero
bytes left them passing — they were pinning the code's own arithmetic,
not the published constant. Replaced with a literal witness of the
published IV plus the NIST SP 800-38A F.2.2 CBC-AES128 vector, and
verified the other way round: zeroing AACS_IV now fails three tests.

The rest are allocation and correctness work on hot paths: the Annex-B
writer in demux_sink allocated and freed a whole-frame Vec per frame,
which for a UHD title is ~200,000 allocations over the mmap threshold
plus the page faults to first-touch each one; it now reuses a buffer on
the writer, and still takes the NAL prefix width from the configuration
record rather than assuming four.

Six findings whose real fix lives in a consumer crate are recorded for
re-filing rather than patched here.
This commit is contained in:
Matthew Jackson
2026-07-29 22:09:52 -07:00
parent 4fcd28b487
commit 0bbceed985
19 changed files with 1342 additions and 126 deletions
+65 -4
View File
@@ -681,10 +681,18 @@ pub struct MkvMuxer<W: Write + Seek> {
cues: Vec<CuePoint>,
frame_count: u64,
/// Frames handed to `write_frame` that were dropped because no cluster was
/// open yet (a cluster only opens on a track-0 video keyframe). If this is
/// non-zero at `finish()` and not a single frame was ever written, the
/// caller produced an empty MKV — surfaced as an error rather than a
/// silently empty file. See `write_frame` for the track-0 invariant.
/// open yet (a cluster only opens on a track-0 video keyframe). See
/// `write_frame` for the track-0 invariant.
///
/// The ALL-dropped case is surfaced as an error by `finish()`, but via
/// `frame_count == 0`, not via this counter. A PARTIAL drop — leading audio /
/// subtitle frames ahead of the first video IDR, or an M2TS whose PMT lists
/// audio before video — is normal enough not to fail the mux, but it used to
/// leave NO record anywhere: the field was incremented at two sites and read
/// nowhere (no log, no error, no accessor), so those frames vanished from the
/// output with `completed = true`, an empty `undelivered_streams`, and nothing
/// in the log. `finish()` now logs the count — that log is the field's only
/// reader, so do not delete it and turn this back into dead bookkeeping.
dropped_pre_cluster: u64,
seek_fixups: Vec<SeekPositionFixup>,
/// Absolute file offset of the CUES SeekHead entry (a fixed 21-byte Seek
@@ -1657,6 +1665,18 @@ impl<W: Write + Seek> MkvMuxer<W> {
if self.frame_count == 0 {
return Err(crate::error::Error::MkvInvalid.into());
}
// Partial pre-cluster drops do not fail the mux (leading audio ahead of the
// first video IDR is normal), but they MUST leave a record: this counter
// was write-only, so frames silently vanished from the output while the run
// reported success. See the field's doc.
if self.dropped_pre_cluster > 0 {
tracing::warn!(
target: "mux",
dropped = self.dropped_pre_cluster,
frames_written = self.frame_count,
"frames were discarded before the first cluster opened (no track-0 video keyframe had arrived yet); they are absent from the output"
);
}
// The source declared no duration up-front (DURATION was reserved as a
// placeholder). Derive the real runtime from the muxed timeline so the
// Segment declares it — and so the BPS tags below can be computed.
@@ -2615,6 +2635,47 @@ mod tests {
);
}
/// Frames dropped before the first cluster opens must be COUNTED, and the
/// count must survive to `finish()` so it can be reported. The counter was
/// incremented at two sites and read nowhere — no log, no error, no accessor —
/// so a partial drop (leading audio/subtitle frames ahead of the first video
/// IDR, or an M2TS whose PMT lists audio before video) silently omitted those
/// frames from the output while the run reported `completed = true` with an
/// empty `undelivered_streams` and nothing in the log. `finish()` now logs it;
/// this pins the accounting the log depends on.
#[test]
fn frames_dropped_before_first_cluster_are_counted() {
let buf = Cursor::new(Vec::new());
let tracks = [make_video_track()];
let mut muxer = MkvMuxer::new(buf, &tracks, None, 60.0, &[]).unwrap();
// Two non-keyframes arrive before any track-0 keyframe: no cluster can be
// open, so both are dropped.
muxer
.write_frame(0, 0, false, &[0x01; 8], None, None)
.unwrap();
muxer
.write_frame(0, 1_000_000, false, &[0x02; 8], None, None)
.unwrap();
assert_eq!(
muxer.dropped_pre_cluster, 2,
"both pre-cluster frames must be counted, not silently lost"
);
assert_eq!(muxer.frame_count, 0, "neither frame was written");
// A keyframe then opens the cluster and is written; the drop count stands
// so `finish()` can still report it.
muxer
.write_frame(0, 2_000_000, true, &[0x03; 8], None, None)
.unwrap();
assert_eq!(muxer.frame_count, 1);
assert_eq!(
muxer.dropped_pre_cluster, 2,
"the drop count must survive to finish(), which reports it"
);
muxer
.finish()
.expect("a mux with one written frame succeeds");
}
#[test]
fn mkv_finish_writes_cues_element() {
// finish() consumes self and flushes the writer, so use the