Files
vphone-cli/sources/FirmwarePatcher/Kernel/JBPatches/KernelJBPatchTaskForPid.swift
Managed via Tart d042596cc0 Complete Swift firmware patcher parity and CLI wiring
Run SwiftFormat on firmware patcher

Remove legacy Python firmware patchers

Fix compare pipeline pyimg4 PATH handling

Restore Python patchers and prefer fresh restore

Update BinaryBuffer.swift

Avoid double scanning in patcher apply

Prefer Python TXM site before fallback

Retarget TXM trustcache finder for 26.1

Remove legacy Python firmware patchers

Fail fast on nested virtualization hosts

Return nonzero on fatal boot startup

Add amfidont helper for signed boot binary

Stage AMFI boot args for next host reboot

Add host preflight for boot entitlements

Fail fast when boot entitlements are unavailable

Switch firmware patch targets to Swift CLI

Record real Swift firmware parity results

Verify Swift firmware pipeline end-to-end parity

Fix Swift firmware pipeline JB dry-run
2026-03-11 15:05:49 +08:00

157 lines
6.1 KiB
Swift

// KernelJBPatchTaskForPid.swift JB kernel patch: task_for_pid bypass
//
// Historical note: derived from the legacy Python firmware patcher during the Swift migration.
import Capstone
import Foundation
extension KernelJBPatcher {
/// NOP the upstream early `pid == 0` reject gate in `task_for_pid`.
///
/// Anchor: `proc_ro_ref_task` string enclosing function.
/// Shape:
/// ldr wPid, [xArgs, #8]
/// ldr xTaskPtr, [xArgs, #0x10]
/// ...
/// cbz wPid, fail
/// mov w1, #0
/// mov w2, #0
/// mov w3, #0
/// mov x4, #0
/// bl port_name_to_task-like helper
/// cbz x0, fail (same fail target)
@discardableResult
func patchTaskForPid() -> Bool {
log("\n[JB] _task_for_pid: upstream pid==0 gate NOP")
guard let strOff = buffer.findString("proc_ro_ref_task") else {
log(" [-] task_for_pid anchor function not found")
return false
}
let refs = findStringRefs(strOff)
guard !refs.isEmpty, let funcStart = findFunctionStart(refs[0].adrpOff) else {
log(" [-] task_for_pid anchor function not found")
return false
}
let searchEnd = min(buffer.count, funcStart + 0x800)
var hits: [Int] = []
var off = funcStart
while off + 0x18 < searchEnd {
let insns = disasm.disassemble(in: buffer.data, at: off, count: 1)
guard let first = insns.first, first.mnemonic == "cbz" else { off += 4; continue }
if let site = matchUpstreamTaskForPidGate(at: off, funcStart: funcStart) {
hits.append(site)
}
off += 4
}
guard hits.count == 1 else {
log(" [-] expected 1 upstream task_for_pid candidate, found \(hits.count)")
return false
}
let patchOff = hits[0]
let va = fileOffsetToVA(patchOff)
emit(patchOff, ARM64.nop,
patchID: "kernelcache_jb.task_for_pid",
virtualAddress: va,
description: "NOP [_task_for_pid pid==0 gate]")
return true
}
// MARK: - Private helpers
private func matchUpstreamTaskForPidGate(at off: Int, funcStart: Int) -> Int? {
let insns = disasm.disassemble(in: buffer.data, at: off, count: 7)
guard insns.count >= 7 else { return nil }
let cbzPid = insns[0], mov1 = insns[1], mov2 = insns[2]
let mov3 = insns[3], mov4 = insns[4], blInsn = insns[5], cbzRet = insns[6]
// cbz wPid, fail
guard cbzPid.mnemonic == "cbz",
let cbzPidOps = cbzPid.aarch64?.operands, cbzPidOps.count == 2,
cbzPidOps[0].type == AARCH64_OP_REG,
cbzPidOps[1].type == AARCH64_OP_IMM
else { return nil }
let failTarget = cbzPidOps[1].imm
// mov w1, #0 / mov w2, #0 / mov w3, #0 / mov x4, #0
guard isMovImmZero(mov1, dstName: "w1"),
isMovImmZero(mov2, dstName: "w2"),
isMovImmZero(mov3, dstName: "w3"),
isMovImmZero(mov4, dstName: "x4")
else { return nil }
// bl helper
guard blInsn.mnemonic == "bl" else { return nil }
// cbz x0, fail (same target)
guard cbzRet.mnemonic == "cbz",
let cbzRetOps = cbzRet.aarch64?.operands, cbzRetOps.count == 2,
cbzRetOps[0].type == AARCH64_OP_REG,
cbzRetOps[1].type == AARCH64_OP_IMM,
cbzRetOps[1].imm == failTarget
else { return nil }
// x0
let retRegName = cbzRet.operandString.components(separatedBy: ",").first?
.trimmingCharacters(in: CharacterSet.whitespaces) ?? ""
guard retRegName == "x0" else { return nil }
// Look backward for ldr wPid, [x?, #8] and ldr xTaskPtr, [x?, #0x10]
let scanStart = max(funcStart, off - 0x18)
var pidLoad: Instruction? = nil
var taskptrLoad: Instruction? = nil
var prevOff = scanStart
while prevOff < off {
let prevInsns = disasm.disassemble(in: buffer.data, at: prevOff, count: 1)
guard let prev = prevInsns.first else { prevOff += 4; continue }
if pidLoad == nil, isWLdrFromXImm(prev, imm: 8) { pidLoad = prev }
if taskptrLoad == nil, isXLdrFromXImm(prev, imm: 0x10) { taskptrLoad = prev }
prevOff += 4
}
guard let pid = pidLoad, taskptrLoad != nil else { return nil }
// pid register must match cbz operand
guard let pidOps = pid.aarch64?.operands, !pidOps.isEmpty,
pidOps[0].reg == cbzPidOps[0].reg
else { return nil }
return off
}
private func isMovImmZero(_ insn: Instruction, dstName: String) -> Bool {
guard insn.mnemonic == "mov",
let ops = insn.aarch64?.operands, ops.count == 2,
ops[0].type == AARCH64_OP_REG,
ops[1].type == AARCH64_OP_IMM, ops[1].imm == 0
else { return false }
let name = insn.operandString.components(separatedBy: ",").first?
.trimmingCharacters(in: CharacterSet.whitespaces) ?? ""
return name == dstName
}
private func isWLdrFromXImm(_ insn: Instruction, imm: Int32) -> Bool {
guard insn.mnemonic == "ldr",
let ops = insn.aarch64?.operands, ops.count >= 2,
ops[0].type == AARCH64_OP_REG,
ops[1].type == AARCH64_OP_MEM,
ops[1].mem.disp == imm
else { return false }
let dstName = insn.operandString.components(separatedBy: ",").first?
.trimmingCharacters(in: CharacterSet.whitespaces) ?? ""
return dstName.hasPrefix("w")
}
private func isXLdrFromXImm(_ insn: Instruction, imm: Int32) -> Bool {
guard insn.mnemonic == "ldr",
let ops = insn.aarch64?.operands, ops.count >= 2,
ops[0].type == AARCH64_OP_REG,
ops[1].type == AARCH64_OP_MEM,
ops[1].mem.disp == imm
else { return false }
let dstName = insn.operandString.components(separatedBy: ",").first?
.trimmingCharacters(in: CharacterSet.whitespaces) ?? ""
return dstName.hasPrefix("x")
}
}