[cocoa] AVStreamDataParser accepts media segments not preceded by an init segment
LayoutTests/media/media-source/media-source-append-media-before-init.html
WebKit's MSE implementation on Cocoa delegates ISO-BMFF parsing to AVStreamDataParser, an AVFoundation private API. The MSE spec mandates a strict ordering: an initialization segment (ftyp+moov) must precede any media segment (moof+mdat). AVStreamDataParser does not enforce this itself — it produces CMSampleBuffers with null CMFormatDescription that fail downstream. Mid-stream format changes (a new ftyp arriving without a preceding abort()/changeType()) trigger an internal CoreMedia -16046 error from MoofManifold that is swallowed silently.
This commit adds a new ISOBMFFPreParser upstream of AVStreamDataParser. It walks ISO-BMFF box headers across appendData() boundaries — without parsing box contents — to reject media segments before any init segment and inject an AVStreamDataParserStreamDataDiscontinuity signal when a new ftyp appears mid-stream. The pre-parser uses BitReader rather than the existing ISOBox::peekBox (which requires JSC::DataView and routes through Gigacage) because SharedBuffer contents are not Gigacage-allocated and that path faults with EXC_BAD_ACCESS. The previously dead AppendFlags::Discontinuity code path is activated for the first time outside abort()/changeType().
Significance
A new stateful binary parser now sits in front of AVStreamDataParser on Apple platforms, walking ISO-BMFF box headers across appendData() boundaries on attacker-supplied, non-Gigacaged memory.
Audit directions
- Box size field decoding. The pre-parser handles all three ISO-BMFF size encodings: standard 32-bit, 64-bit extended (size field == 1, followed by an 8-byte length), and open-ended (size == 0, "rest of stream"). Integer overflow when computing the next-box offset from a 64-bit attacker-controlled size is the classic attack here. The 32→64-bit promotion path and the
size==0sentinel deserve close scrutiny. - Cross-boundary partial header state (
m_pendingHeaderBytes). Headers split across twoappendData()calls are reassembled via a byte-accumulation buffer. Off-by-one errors in how many bytes are consumed vs. buffered could corrupt the parser's view of box boundaries, misclassifying a media segment as an init segment or vice versa. - Append split logic. When a new
ftypis detected mid-append, the pre-parser computes a byte offset and slices theSharedBufferinto two parts. Arithmetic errors — particularly given varying header sizes (8 bytes for 32-bit, 16 bytes for 64-bit extended) — would send misaligned data to AVStreamDataParser. - Reactivated
AppendFlags::Discontinuitypath. The flag was never reached outsideresetParserState(). Any assumptions in downstream handling (e.g., what stateAVStreamDataParseris expected to be in when the flag arrives) have never been tested in the mid-stream re-init scenario. BitReaderon non-Gigacaged memory. The commit explicitly documents thatISOBox::peekBoxfaults onSharedBuffermemory and usesBitReaderinstead. IfBitReaderhas any bounds-checking gaps and the pre-parser misjudges remaining buffer length (e.g., via a truncated 64-bit size field), this path operates on attacker data without the Gigacage safety net.