Fix rc5 audit findings: keydb doc, pipeline ordering, hot-loop Arc, tests
- keydb.rs: separate default_path()/no_home_dir() doc blocks; correct the false XDG lock-step claim (Linux write path uses $HOME, ignores XDG_CONFIG_HOME; read-side search also checks XDG_CONFIG_HOME). - io/pipeline.rs: use Release/Acquire on the abandoned flag so a leaked consumer reliably skips close() on weak memory models (ARM64/POWER), not just x86 TSO. - mux/disc.rs: cache the decrypt-loss Arc at construction; lost_bytes() no longer clones an Arc per frame on the mux hot path. - disc/dvd.rs: assert display_aspect mapping for both 16:9 (PAL test) and 4:3 (NTSC test). - mux/resolve.rs: extract css_error_aborts() helper and unit-test the scrambled-but-uncracked CSS guard (Fix 6) incl. the --raw exemption. - aacs/keys.rs: add unit tests for mkb_type_raw/mkb_type/mkb_is_uhd and MkbType (Category C 2.0 UHD, prerecorded 1.0, no-0x10-record None). - release.yml: publish job needs [verify, test] so a failing test suite blocks crates.io publication.
This commit is contained in:
+25
-1
@@ -249,6 +249,17 @@ fn css_key_missing(raw: bool, has_css: bool, keys: &crate::decrypt::DecryptKeys)
|
||||
!raw && has_css && matches!(keys, crate::decrypt::DecryptKeys::None)
|
||||
}
|
||||
|
||||
/// Scrambled-but-uncracked CSS guard (Fix 6). Returns `true` when decryption
|
||||
/// is requested (`!raw`) and the scan recorded a hard CSS error
|
||||
/// (`has_css_error` — `disc.css_error.is_some()`), meaning the content is
|
||||
/// scrambled but no title key was recovered (so `disc.css` is `None`). Muxing
|
||||
/// that case would pass scrambled MPEG through as plaintext, so the caller
|
||||
/// fails fast with [`Error::CssKeyMissing`]. `--raw` is exempt (skips
|
||||
/// decryption), so it always returns `false`.
|
||||
fn css_error_aborts(raw: bool, has_css_error: bool) -> bool {
|
||||
!raw && has_css_error
|
||||
}
|
||||
|
||||
/// Open a PES input stream (produces PES frames).
|
||||
pub fn input(url: &str, opts: &InputOptions) -> io::Result<Box<dyn crate::pes::Stream>> {
|
||||
let parsed = parse_url(url);
|
||||
@@ -290,7 +301,7 @@ pub fn input(url: &str, opts: &InputOptions) -> io::Result<Box<dyn crate::pes::S
|
||||
// as "unencrypted" and the scrambled MPEG would mux as plaintext
|
||||
// garbage at exit 0. Surface the recorded hard error instead.
|
||||
// `--raw` skips decryption, so it is exempt.
|
||||
if !opts.raw && disc.css_error.is_some() {
|
||||
if css_error_aborts(opts.raw, disc.css_error.is_some()) {
|
||||
return Err(crate::error::Error::CssKeyMissing.into());
|
||||
}
|
||||
// No-key guard: if decryption is requested (not --raw) and the disc
|
||||
@@ -658,6 +669,7 @@ fn build_m2ts_pipeline<R: std::io::Read + Send + 'static>(
|
||||
mod tests {
|
||||
use super::StreamUrl;
|
||||
use super::aacs_key_missing;
|
||||
use super::css_error_aborts;
|
||||
use super::css_key_missing;
|
||||
use super::parse_url;
|
||||
use super::validate_network_addr;
|
||||
@@ -779,6 +791,18 @@ mod tests {
|
||||
assert!(!css_key_missing(false, false, &DecryptKeys::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn css_error_field_aborts_unless_raw() {
|
||||
// Fix 6: a scrambled-but-uncracked DVD records a hard error in
|
||||
// `disc.css_error` (css is None). With decryption requested the
|
||||
// input() guard must abort with CssKeyMissing.
|
||||
assert!(css_error_aborts(false, true));
|
||||
// --raw skips decryption → never aborts on the css_error field.
|
||||
assert!(!css_error_aborts(true, true));
|
||||
// No recorded css_error → the guard does not fire.
|
||||
assert!(!css_error_aborts(false, false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn raw_never_aborts() {
|
||||
// --raw skips decryption — must never hit the no-key abort, even on an
|
||||
|
||||
Reference in New Issue
Block a user