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
+31
-21
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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) }
|
||||
|
||||
Reference in new issue
Block a user