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

+31 -21
View File
@@ -8,8 +8,14 @@ import SwiftUI
enum VersionGate {
enum Result {
case supported(major: Int, minor: Int, build: String)
case unsupported(major: Int, minor: Int, build: String)
case supported(major: Int, minor: Int, patch: Int, build: String)
case unsupported(major: Int, minor: Int, patch: Int, build: String)
}
/// "27.0" for a zero patch, "27.0.1" when there is one. The patch is part of the
/// answer — a 27.0.1 device that reports "27.0" is a false reading.
static func versionString(major: Int, minor: Int, patch: Int) -> String {
patch != 0 ? "\(major).\(minor).\(patch)" : "\(major).\(minor)"
}
static func evaluate() -> Result {
@@ -33,12 +39,12 @@ enum VersionGate {
supported = false // 27.2+ / 28+ — patched
}
// An explicit override exists for research builds where the version string lies.
if ProcessInfo.processInfo.environment["CINDER27_FORCE_GATE"] == "1" {
return .supported(major: v.majorVersion, minor: v.minorVersion, build: build)
if ProcessInfo.processInfo.environment["CINDER27_FORCE_GATE"] == "1" {
return .supported(major: v.majorVersion, minor: v.minorVersion, patch: v.patchVersion, build: build)
}
return supported
? .supported(major: v.majorVersion, minor: v.minorVersion, build: build)
: .unsupported(major: v.majorVersion, minor: v.minorVersion, build: build)
? .supported(major: v.majorVersion, minor: v.minorVersion, patch: v.patchVersion, build: build)
: .unsupported(major: v.majorVersion, minor: v.minorVersion, patch: v.patchVersion, build: build)
}
static var isSupported: Bool {
@@ -53,17 +59,17 @@ struct GateView: View {
enum Phase {
case checking
case supported(major: Int, minor: Int, build: String)
case unsupported(major: Int, minor: Int, build: String)
case supported(major: Int, minor: Int, patch: Int, build: String)
case unsupported(major: Int, minor: Int, patch: Int, build: String)
}
var body: some View {
ZStack {
T.bg.ignoresSafeArea()
if entered, case let .supported(major, minor, build) = phase {
if entered, case let .supported(major, minor, patch, build) = phase {
RootView()
.environment(\.gateInfo, GateInfo(major: major, minor: minor, build: build))
.environment(\.gateInfo, GateInfo(major: major, minor: minor, patch: patch, build: build))
.transition(.opacity)
} else {
content
@@ -106,7 +112,7 @@ struct GateView: View {
}
.padding(.top, 20)
case let .supported(major, minor, build):
case let .supported(major, minor, patch, build):
Card {
VStack(alignment: .leading, spacing: 10) {
HStack(spacing: 8) {
@@ -117,7 +123,7 @@ struct GateView: View {
.font(.system(size: 15, weight: .semibold, design: .rounded))
.foregroundColor(T.good)
}
KeyValueRow(key: t("gate.detected"), value: "iOS \(major).\(minor)")
KeyValueRow(key: t("gate.detected"), value: VersionGate.versionString(major: major, minor: minor, patch: patch))
KeyValueRow(key: t("gate.build"), value: build)
KeyValueRow(key: t("gate.required"), value: "17.0 – 27.1")
}
@@ -129,7 +135,7 @@ struct GateView: View {
}
.padding(.horizontal, 24)
case let .unsupported(major, minor, build):
case let .unsupported(major, minor, patch, build):
Card {
VStack(alignment: .leading, spacing: 10) {
HStack(spacing: 8) {
@@ -140,7 +146,7 @@ struct GateView: View {
.font(.system(size: 15, weight: .semibold, design: .rounded))
.foregroundColor(T.bad)
}
KeyValueRow(key: t("gate.detected"), value: "iOS \(major).\(minor)", tint: T.bad)
KeyValueRow(key: t("gate.detected"), value: VersionGate.versionString(major: major, minor: minor, patch: patch), tint: T.bad)
KeyValueRow(key: t("gate.build"), value: build)
KeyValueRow(key: t("gate.required"), value: "17.0 – 27.1")
Divider().overlay(T.stroke)
@@ -170,8 +176,8 @@ struct GateView: View {
private var phaseText: String {
switch phase {
case .checking: return "checking"
case let .supported(m, n, _): return "ok-\(m).\(n)"
case let .unsupported(m, n, _): return "no-\(m).\(n)"
case let .supported(m, n, p, _): return "ok-\(m).\(n).\(p)"
case let .unsupported(m, n, p, _): return "no-\(m).\(n).\(p)"
}
}
@@ -179,10 +185,10 @@ struct GateView: View {
phase = .checking
DispatchQueue.main.asyncAfter(deadline: .now() + 0.45) {
switch VersionGate.evaluate() {
case let .supported(major, minor, build):
phase = .supported(major: major, minor: minor, build: build)
case let .unsupported(major, minor, build):
phase = .unsupported(major: major, minor: minor, build: build)
case let .supported(major, minor, patch, build):
phase = .supported(major: major, minor: minor, patch: patch, build: build)
case let .unsupported(major, minor, patch, build):
phase = .unsupported(major: major, minor: minor, patch: patch, build: build)
}
}
}
@@ -191,11 +197,15 @@ struct GateView: View {
struct GateInfo {
let major: Int
let minor: Int
let patch: Int
let build: String
/// The full detected version, patch included — what the gate actually read.
var osVersion: String { VersionGate.versionString(major: major, minor: minor, patch: patch) }
}
private struct GateInfoKey: EnvironmentKey {
static let defaultValue = GateInfo(major: 0, minor: 0, build: "—")
static let defaultValue = GateInfo(major: 0, minor: 0, patch: 0, build: "—")
}
extension EnvironmentValues {
+1
View File
@@ -293,6 +293,7 @@ struct DeviceModel {
"iPhone19,2": "iPhone 18 Pro Max",
"iPhone19,3": "iPhone 18",
"iPhone19,4": "iPhone 18 Air",
"iPhone19,7": "iPhone 18 Pro Max",
]
return table[machine] ?? machine
}
+4 -2
View File
@@ -246,9 +246,11 @@ enum MachO {
}
guard removed > 0 else { return (data, 0) }
// rewrite the command stream in place, then zero the tail of the old region
// rewrite the command stream in place, then zero the tail of the old region.
// sizeofcmds is attacker-controlled in a malformed header — clamp before indexing,
// or the zeroing loop below walks off the end of the image.
let streamStart = h.headerSize
let oldEnd = streamStart + Int(h.sizeofcmds)
let oldEnd = min(streamStart + Int(h.sizeofcmds), out.count)
out.replaceSubrange(streamStart..<(streamStart + kept.count), with: kept)
if streamStart + kept.count < oldEnd {
for i in (streamStart + kept.count)..<oldEnd { out[i] = 0 }
-2
View File
@@ -466,7 +466,6 @@ enum Decmpfs {
out.append(contentsOf: B.le32(typeZlibChunked))
out.append(contentsOf: B.le64(UInt64(uncompressedSize)))
let headerSize = 16 + (chunkCount + 1) * 4
var chunkBlobs: [[UInt8]] = []
for _ in 0..<chunkCount {
// flag 0x00 + zlib stream that decompresses to producePerChunk bytes of 0x41
@@ -498,7 +497,6 @@ enum Decmpfs {
}
offsets.append(running)
for o in offsets { out.append(contentsOf: B.le32(o)) }
_ = headerSize
for blob in chunkBlobs { out.append(contentsOf: blob) }
return out
}
+9 -3
View File
@@ -413,10 +413,16 @@ enum GPTPayload {
let entryLBA = image.withUnsafeBytes { $0.load(fromByteOffset: 512 + 72, as: UInt64.self) }
let entryCount = image.withUnsafeBytes { $0.load(fromByteOffset: 512 + 80, as: UInt32.self) }
let entrySize = image.withUnsafeBytes { $0.load(fromByteOffset: 512 + 84, as: UInt32.self) }
// every one of these is attacker-controlled in a hand-crafted image; the Int
// conversions trap on huge values, and the multiply overflows. Bound them to
// values that can only index inside the image we already hold.
let safeLBA = entryLBA > 0 ? min(entryLBA, UInt64(image.count / 512)) : 0
let safeCount = min(Int(entryCount), 4096)
let safeSize = entrySize > 0 ? min(Int(entrySize), 512) : 128
lines.append(tl("GPT 头: 条目表 LBA ") + "\(entryLBA)" + tl(" · ") + "\(entryCount)" + tl(" 项 · 每项 ") + "\(entrySize)" + tl(" B"))
let base = Int(entryLBA) * 512
for i in 0..<Int(entryCount) {
let off = base + i * Int(entrySize)
let base = Int(safeLBA) * 512
for i in 0..<safeCount {
let off = base + i * safeSize
guard off + 128 <= image.count else { break }
var units: [UInt16] = []
for k in 0..<36 {
+13 -6
View File
@@ -317,13 +317,20 @@ enum Runners {
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
throw LabError(message: tl("上下文创建失败"))
}
// drawing forces the charstring interpreter to run
for g in 1..<min(Int(glyphCount), 8) {
var glyph = CGGlyph(g)
var position = CGPoint(x: 20, y: CGFloat(40 * (g + 1)))
CTFontDrawGlyphs(ctFont, &glyph, &position, 1, ctx)
// drawing forces the charstring interpreter to run.
// glyphCount == 0 is a real malformed-font shape (the POCs feed exactly those),
// and `1..<0` would trap — guard the range instead of assuming the count.
let upper = min(Int(glyphCount), 8)
var drawn = 0
if upper > 1 {
for g in 1..<upper {
var glyph = CGGlyph(g)
var position = CGPoint(x: 20, y: CGFloat(40 * (g + 1)))
CTFontDrawGlyphs(ctFont, &glyph, &position, 1, ctx)
drawn += 1
}
}
return tl("字体加载成功 name=") + "\(name)" + tl(" glyphs=") + "\(glyphCount)" + tl(",已绘制 ") + "\(min(Int(glyphCount), 8) - 1)" + tl(" 个字形")
return tl("字体加载成功 name=") + "\(name)" + tl(" glyphs=") + "\(glyphCount)" + tl(",已绘制 ") + "\(drawn)" + tl(" 个字形")
}
// ---- Model I/O (libusd_ms)
+4 -4
View File
@@ -174,10 +174,7 @@ enum Identity {
rows.append((tl("主机名"), sysctlString("kern.hostname") ?? "—"))
rows.append((tl("启动 UUID"), sysctlString("kern.bootsessionuuid") ?? "—"))
rows.append((tl("启动时间"), sysctlString("kern.boottime") ?? "—"))
if let model = sysctlString("hw.machine") {
rows.append((tl("市场名称"), DeviceModel.current().marketingName))
_ = model
}
rows.append((tl("市场名称"), DeviceModel.current().marketingName))
rows.append((tl("广告标识符"), ASIdentifierSummary.current))
return rows
}
@@ -359,6 +356,9 @@ struct MachOInfo {
enum MachOInspector {
static func inspect(_ path: String) -> MachOInfo? {
guard let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { return nil }
// a Mach-O header needs at least the magic; anything shorter is not one. The
// load below would read past the buffer (or hit a nil base on empty Data).
guard data.count >= 4 else { return nil }
var info = MachOInfo()
let magic = data.withUnsafeBytes { $0.load(as: UInt32.self) }