Files
vphone-cli/research/kernel_patch_jb/patch_task_for_pid.md
Lakr 6c4165c7fe docs: fix formatting in kernel_patch_jb MD files
Apply whitespace and formatting cleanups across research/kernel_patch_jb/*.md: add missing blank lines for readability, remove extraneous trailing blank lines, and adjust a small inline spacing/punctuation in patch_vm_map_protect.md. No semantic changes to content.
2026-03-06 23:11:14 +08:00

5.6 KiB

B15 patch_task_for_pid

Goal

Keep the jailbreak task_for_pid patch aligned with the known-good upstream design in /Users/qaq/Desktop/patch_fw.py unless IDA + XNU clearly prove that upstream is wrong.

  • Preferred upstream target: patch(0xFC383C, 0xD503201F).
  • Final rework result: match.
  • PCC 26.1 research hit: file offset 0x00FC383C, VA 0xFFFFFE0007FC783C.
  • PCC 26.1 release hit: file offset 0x00F8783C.

What Gets Patched

The patch NOPs the early pid == 0 reject gate in task_for_pid, before the call that resolves the target task port.

On PCC 26.1 research the validated sequence is:

0xFFFFFE0007FC7828  ldr w23, [x8, #8]
0xFFFFFE0007FC782C  ldr x19, [x8, #0x10]
0xFFFFFE0007FC783C  cbz w23, 0xFFFFFE0007FC79CC   ; patched
0xFFFFFE0007FC7840  mov w1, #0
0xFFFFFE0007FC7844  mov w2, #0
0xFFFFFE0007FC7848  mov w3, #0
0xFFFFFE0007FC784C  mov x4, #0
0xFFFFFE0007FC7850  bl  <helper>
0xFFFFFE0007FC7854  cbz x0, 0xFFFFFE0007FC79CC

Upstream Match vs Divergence

Final status: match

  • Upstream patch_fw.py uses file offset 0xFC383C.
  • The reworked matcher now emits exactly 0xFC383C on PCC 26.1 research.
  • The corresponding PCC 26.1 release hit is 0xF8783C, which is the expected variant-shifted analogue of the same in-function gate.

Rejected drift design

The previous local rework had diverged to two later deny-return rewrites in small helper functions.

That divergence is rejected because:

  • it does not match the known-good upstream site,
  • the XNU source still explicitly says /* Always check if pid == 0 */ and immediately returns failure,
  • IDA on PCC 26.1 research still shows the same early cbz wPid, fail gate at the exact upstream offset,
  • the helper-rewrite path broadens behavior more than necessary and is computationally more expensive at runtime.

XNU Cross-Reference

Source: research/reference/xnu/bsd/kern/kern_proc.c:5715

/* Always check if pid == 0 */
if (pid == 0) {
    (void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
    AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
    return KERN_FAILURE;
}

Fact

  • The source-level first authorization gate in task_for_pid() is the pid == 0 rejection.
  • The validated PCC 26.1 research instruction at 0xFFFFFE0007FC783C is the direct binary analogue of that source gate.

Inference

NOPing this early cbz is the narrowest upstream-compatible jailbreak bypass because it removes only the unconditional pid == 0 failure gate, while leaving the later proc_find(), task_for_pid_posix_check(), and task lookup flow structurally intact.

Anchor Class

  • Primary runtime anchor class: string + heuristic.
  • Concrete string anchor: "proc_ro_ref_task", which lives inside the same stripped function body on PCC 26.1 research.
  • Why this anchor was chosen: the embedded symtable is effectively empty, IDA names are not stable, but this in-function string reliably recovers the enclosing function so the heuristic scan stays local instead of walking the whole kernel.

Runtime Matcher Design

The runtime matcher is intentionally single-path and upstream-aligned:

  1. Recover the enclosing function from the in-image string "proc_ro_ref_task".
  2. Scan only that function for the unique local sequence:
    • ldr wPid, [xArgs, #8]
    • ldr xTaskPtr, [xArgs, #0x10]
    • cbz wPid, fail
    • mov w1, #0
    • mov w2, #0
    • mov w3, #0
    • mov x4, #0
    • bl
    • cbz x0, fail
  3. Patch the first cbz with NOP.

This avoids unstable IDA naming while keeping the reveal logic close to the exact upstream gate.

Why This Should Generalize

This matcher should survive PCC 26.1 research, PCC 26.1 release, and likely nearby release variants such as 26.3 because it relies on:

  • the stable syscall argument layout (pid at +8, task port output at +0x10),
  • the narrow early-failure ABI shape around port_name_to_task(), and
  • a single local fail target shared by cbz wPid and the post-helper cbz x0.

Runtime cost remains reasonable:

  • one full sequential decode of kern_text,
  • no repeated nested scans,
  • one exact candidate accepted.

Validation

Focused dry-run

Validated locally on extracted raw kernels:

  • PCC 26.1 research: hit at 0x00FC383C
  • PCC 26.1 release: hit at 0x00F8783C

Both variants emit exactly one patch:

  • NOP [_task_for_pid pid==0 gate]

Match verdict

  • Upstream reference /Users/qaq/Desktop/patch_fw.py: match
  • IDA PCC 26.1 research control-flow: match
  • XNU task_for_pid early gate semantics: match

Files

  • Patcher: scripts/patchers/kernel_jb_patch_task_for_pid.py
  • Analysis doc: research/kernel_patch_jb/patch_task_for_pid.md

2026-03-06 Rework

  • Upstream target (/Users/qaq/Desktop/patch_fw.py): match.
  • Final research site: 0x00FC383C (0xFFFFFE0007FC783C).
  • Anchor class: string + heuristic. Runtime reveal recovers the enclosing function from the in-image "proc_ro_ref_task" string, then finds the unique upstream local ldr pid ; ldr task_ptr ; cbz pid ; mov w1/w2/w3,#0 ; mov x4,#0 ; bl ; cbz x0 pattern.
  • Why this site: it is the exact known-good upstream pid == 0 reject gate, and XNU still models it as the first unconditional failure path in task_for_pid().
  • Release/generalization rationale: the local ABI/control-flow pattern is narrow and stable across stripped kernels, while avoiding reliance on symbol names.
  • Performance note: one string-xref resolution plus a single bounded local scan (+0x800 window) because the stripped-function end detector truncates this function too early on current PCC 26.1 images; still no whole-kernel repeated semantic rescans.
  • Focused PCC 26.1 research dry-run: pending main-agent validation.