0.31.0: hardening and correctness pass across mux, codec, AACS/CSS, UDF/MPLS/CLPI, recovery, drive/SCSI, labels, and I/O

Library-wide review-and-fix pass: tightened AACS keydb/handshake/variant
handling and trailing-partial-unit policy, corrected MPLS mark offset and
added UDF allocation bounds, hardened the mux/codec framing and M2TS paths,
guarded SCSI READ CAPACITY short transfers and unified error mapping, added
overflow guards on untrusted disc input, and made prefetch shutdown
deterministic. Release profile now builds with thin LTO + single codegen unit.
This commit is contained in:
Matthew Jackson
2026-06-07 17:37:38 -07:00
parent 5b6ea8f5c4
commit 061f68594a
128 changed files with 11838 additions and 3831 deletions
+95 -21
View File
@@ -35,6 +35,11 @@ impl NetworkStream {
/// Sends FMKV metadata header on first write.
pub fn connect(addr: &str) -> io::Result<Self> {
let stream = TcpStream::connect(addr)?;
// The sender is the latency-sensitive side; set nodelay here too
// (the listen side already does) so the final sub-MSS flush after
// finish() isn't held by Nagle. The 256 KB BufWriter coalesces
// bulk writes, so this only affects the tail.
stream.set_nodelay(true)?;
Ok(Self {
disc_title: DiscTitle::empty(),
mode: Mode::Write {
@@ -44,7 +49,13 @@ impl NetworkStream {
})
}
/// Set stream metadata (for write side). Returns self for chaining.
/// Set stream metadata (write side only). Returns self for chaining.
///
/// Only meaningful on a [`connect`](Self::connect)-constructed
/// (write) stream — the title is sent in the FMKV header on first
/// write. On a [`listen`](Self::listen)-constructed (read) stream
/// the stored title is immediately overwritten by the header read in
/// `listen()`, so calling `meta()` there is a silent no-op.
pub fn meta(mut self, dt: &DiscTitle) -> Self {
self.disc_title = dt.clone();
self
@@ -52,8 +63,19 @@ impl NetworkStream {
/// Listen for an incoming connection and read from it.
/// Extracts FMKV metadata header from the sender.
///
/// Accepts exactly one connection; the listening socket is dropped after
/// `accept`, so the bound port is freed and any subsequent connection
/// attempt to the same address is refused.
pub fn listen(addr: &str) -> io::Result<Self> {
let listener = TcpListener::bind(addr)?;
Self::accept_from(TcpListener::bind(addr)?)
}
/// Accept one connection from an already-bound listener and read from it.
/// Lets a caller bind first (learning the actual port for an ephemeral
/// `:0` bind) and hand the listener in, closing the bind/drop/re-bind race
/// that `listen(addr)` would otherwise have.
pub fn accept_from(listener: TcpListener) -> io::Result<Self> {
let (stream, _peer) = listener.accept()?;
stream.set_nodelay(true)?;
let mut reader = BufReader::with_capacity(NET_BUF_SIZE, stream);
@@ -70,6 +92,23 @@ impl NetworkStream {
}
}
/// Write the FMKV metadata header exactly once, before any frames. Always
/// writes (even when the title has no streams) so the receiver's
/// `read_header()` always finds the magic and never falls into the
/// NoMetadata path on a zero-frame stream.
fn ensure_header_written(
writer: &mut BufWriter<TcpStream>,
header_written: &mut bool,
disc_title: &DiscTitle,
) -> io::Result<()> {
if !*header_written {
let m = meta::M2tsMeta::from_title(disc_title);
meta::write_header(writer, &m)?;
*header_written = true;
}
Ok(())
}
impl crate::pes::Stream for NetworkStream {
fn read(&mut self) -> io::Result<Option<crate::pes::PesFrame>> {
match &mut self.mode {
@@ -82,22 +121,24 @@ impl crate::pes::Stream for NetworkStream {
Mode::Write {
writer,
header_written,
..
} => {
if !*header_written {
if !self.disc_title.streams.is_empty() {
let m = meta::M2tsMeta::from_title(&self.disc_title);
meta::write_header(&mut *writer, &m)?;
}
*header_written = true;
}
ensure_header_written(writer, header_written, &self.disc_title)?;
frame.serialize(writer)
}
_ => Err(crate::error::Error::StreamReadOnly.into()),
}
}
fn finish(&mut self) -> io::Result<()> {
if let Mode::Write { writer, .. } = &mut self.mode {
if let Mode::Write {
writer,
header_written,
} = &mut self.mode
{
// Always emit the FMKV header before shutdown, even for a
// zero-frame stream (e.g. a title that produced no PES frames).
// Without it the receiver's read_header() sees a clean EOF and
// rejects the stream with NoMetadata.
ensure_header_written(writer, header_written, &self.disc_title)?;
writer.flush()?;
writer.get_ref().shutdown(std::net::Shutdown::Write)?;
}
@@ -156,19 +197,21 @@ mod tests {
}
#[test]
#[ignore] // Requires TCP; may be flaky in CI environments
fn network_pes_roundtrip() {
use crate::pes;
use std::sync::mpsc;
// The listener thread owns the bound socket and reports its actual
// local address back over a channel before accept(). The main thread
// connects only after receiving the address — no bind/drop/re-bind
// window, no sleep-as-synchronisation.
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let port = listener.local_addr().unwrap().port();
drop(listener);
let addr = format!("127.0.0.1:{}", port);
let addr_clone = addr.clone();
let addr = listener.local_addr().unwrap();
let (addr_tx, addr_rx) = mpsc::channel();
let handle = std::thread::spawn(move || {
let mut ns = NetworkStream::listen(&addr_clone).unwrap();
addr_tx.send(addr).unwrap();
let mut ns = NetworkStream::accept_from(listener).unwrap();
let info = pes::Stream::info(&ns).clone();
let mut frames = Vec::new();
while let Ok(Some(f)) = pes::Stream::read(&mut ns) {
@@ -177,10 +220,9 @@ mod tests {
(info, frames)
});
std::thread::sleep(std::time::Duration::from_millis(50));
let addr = addr_rx.recv().unwrap();
let dt = sample_title();
let mut writer = NetworkStream::connect(&addr).unwrap().meta(&dt);
let mut writer = NetworkStream::connect(&addr.to_string()).unwrap().meta(&dt);
let frame = pes::PesFrame {
track: 0,
pts: 90000,
@@ -199,6 +241,38 @@ mod tests {
assert_eq!(frames[0].pts, 90000);
}
#[test]
fn network_zero_frame_finish_still_sends_header() {
use crate::pes;
use std::sync::mpsc;
// A title that produces no PES frames must still send the FMKV header
// on finish(), so the receiver gets the metadata instead of rejecting
// the stream with NoMetadata on a clean EOF.
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
let (addr_tx, addr_rx) = mpsc::channel();
let handle = std::thread::spawn(move || {
addr_tx.send(addr).unwrap();
// listen()'s read_header must succeed (header present), not error.
let ns = NetworkStream::accept_from(listener).unwrap();
pes::Stream::info(&ns).playlist.clone()
});
let addr = addr_rx.recv().unwrap();
let dt = sample_title();
let mut writer = NetworkStream::connect(&addr.to_string()).unwrap().meta(&dt);
// No write() at all — straight to finish().
pes::Stream::finish(&mut writer).unwrap();
let playlist = handle.join().unwrap();
assert_eq!(
playlist, "NetworkTest",
"zero-frame finish() must still deliver the metadata header"
);
}
#[test]
fn network_empty_addr_errors() {
let result = NetworkStream::connect("");