fix(avlivewire): cap demuxer payload length
A corrupt header with a huge UInt32 length made feed buffer forever waiting for bytes that never arrive. Add an 8 MB max payload cap; a header exceeding it is treated as corrupt, its magic is skipped, and the demuxer resyncs on the next frame.
This commit is contained in:
@@ -6,6 +6,10 @@ public struct StreamDemuxer {
|
||||
public let payload: Data
|
||||
}
|
||||
|
||||
/// Largest plausible payload (8 MB) — comfortably covers any HEVC
|
||||
/// access unit. A header claiming more is treated as corrupt.
|
||||
public static let maxPayloadLength: UInt32 = 8 * 1024 * 1024
|
||||
|
||||
private var buffer = Data()
|
||||
public init() {}
|
||||
|
||||
@@ -24,6 +28,12 @@ public struct StreamDemuxer {
|
||||
if start > 0 { buffer.removeFirst(start) }
|
||||
guard buffer.count >= FrameHeader.byteCount,
|
||||
let h = FrameHeader(decoding: buffer) else { break }
|
||||
if h.length > Self.maxPayloadLength {
|
||||
// Implausible length — corrupt header; skip the magic
|
||||
// and resync on the next one.
|
||||
buffer.removeFirst(FrameHeader.magic.count)
|
||||
continue
|
||||
}
|
||||
let total = FrameHeader.byteCount + Int(h.length)
|
||||
guard buffer.count >= total else { break }
|
||||
let payloadStart = buffer.index(
|
||||
|
||||
@@ -38,4 +38,29 @@ final class StreamDemuxerTests: XCTestCase {
|
||||
XCTAssertEqual(out.count, 1)
|
||||
XCTAssertEqual(out[0].payload, Data([7]))
|
||||
}
|
||||
|
||||
func testPartialMagicAtBoundary() {
|
||||
var d = StreamDemuxer()
|
||||
XCTAssertTrue(d.feed(Data([0x41, 0x56, 0x4C])).isEmpty)
|
||||
let payload = Data([42])
|
||||
let h = FrameHeader(tag: .meta, pid: 0, timestamp: 0,
|
||||
length: UInt32(payload.count))
|
||||
var rest = Data([0x31])
|
||||
rest.append(h.encoded().dropFirst(4))
|
||||
rest.append(payload)
|
||||
let out = d.feed(rest)
|
||||
XCTAssertEqual(out.count, 1)
|
||||
XCTAssertEqual(out[0].payload, payload)
|
||||
}
|
||||
|
||||
func testSkipsCorruptOversizedLength() {
|
||||
var d = StreamDemuxer()
|
||||
// Header claiming a 4 GB payload, then a valid frame after.
|
||||
let bad = FrameHeader(tag: .video, pid: 0, timestamp: 0,
|
||||
length: UInt32.max).encoded()
|
||||
let good = frame(.video, Data([5, 5]))
|
||||
let out = d.feed(bad + good)
|
||||
XCTAssertEqual(out.count, 1)
|
||||
XCTAssertEqual(out[0].payload, Data([5, 5]))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user