mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-04-05 04:59:05 +08:00
Included commits: - f8a54b8 Update JB kernel patch research notes Refresh and revalidate jailbreak kernel-patcher documentation and runtime-verification notes. Key updates: re-analyzed B13 (patch_bsd_init_auth) and retargeted recommended site to the FSIOC_KERNEL_ROOTAUTH return check in bsd_init rather than the old ldr/cbz/bl heuristic; clarified preferred NOP-of-CBNZ vs forcing ioctl return. Reworked C21 (patch_cred_label_update_execve) to preserve AMFI exec-time flow and instead clear restrictive csflags in a success-tail trampoline; disabled in default schedule until boot validation. Documented that C23 (patch_hook_cred_label_update_execve) was mis-targeting the wrapper (sub_FFFFFE00093D2CE4) instead of the real hook body (_hook_cred_label_update_execve), explaining boot failures and recommending retargeting. Noted syscallmask and vm_fault matcher problems (patch_syscallmask_apply_to_proc historical hit targeted _profile_syscallmask_destroy; patch_vm_fault_enter_prepare matcher resolves to pmap_lock_phys_page path), and updated the runtime-verification summary with follow-up findings and which methods are temporarily commented out/disabled in the default KernelJBPatcher schedule pending staged re-validation. - 6ebac65 fix: patch_bsd_init_auth - 5b224d3 fix: patch_io_secure_bsd_root - e6806bf docs: update patch notes - 0d89c5c Retarget vm_fault_enter_prepare jailbreak patch - 6b9d79b Rework C21 late-exit cred_label patch - ece8cc0 Clean C21 mov matcher encodings - ad2ea7c enabled fixed patch_cred_label_update_execve - c37b6b1 Rebuild syscallmask C22 patch - 363dd7a Rebuild JB C23 as faithful upstream trampoline - 129e648 Disable IOUC MACF; rebuild kcall10 & C22 docs Re-evaluate and rework several JB kernel patches and docs: mark patch_iouc_failed_macf as reverted/disabled (repo-local, over-broad early-return) and replace its patcher with a no-op implementation to emit zero writes by default; update research notes to explain the reanalysis and rationale. Rebuild patch_kcall10: replace the historical 10-arg design with an ABI-correct syscall-439 cave (target + 7 args -> uint64 return), add a new cave builder and munge32 reuse logic in the kcall10 patcher, and enable the method in KernelJBPatcher group. Clarify syscallmask (C22) semantics in docs: upstream C22 is an all-ones-mask retarget (not a NULL install) and keep the rebuilt all-ones wrapper as the authoritative baseline. Misc: minor refactors and helper additions (chained-pointer helpers, cave size/constants, validation and dry-run safeguards) to improve correctness and alignment with IDA/runtime verification. - e1b2365 Rebuild kcall10 as ABI-correct syscall cave - 23090d0 fix patch_iouc_failed_macf - 0056be2 Normalize formatting in research docs Apply whitespace and formatting cleanup across research markdown files for consistency and readability. Adjust table alignment and spacing in 00_patch_comparison_all_variants.md, normalize list/indentation spacing in patch_bsd_init_auth.md and patch_syscallmask_apply_to_proc.md, and add/clean blank lines and minor spacing in patch_kcall10.md. These are non-functional documentation changes only.
10 KiB
10 KiB
C24 patch_kcall10
Status (2026-03-06, PCC 26.1 re-analysis)
- Treat all older
kcall10notes in this repo as historical / untrusted unless they match the facts below. - Current verdict for the legacy upstream-style design: it was ABI-incorrect for PCC 26.1 and has been replaced in the patcher with a rebuilt ABI-correct syscall-cave design.
- Scope of this document: single-patch re-research only, focused exclusively on the
kcall10kernel-call patch itself.
Goal
- Repurpose
SYS_kas_info(syscall 439) into a usable kernel-call primitive for jailbreak workflows. - Keep the hook on a syscall slot that is already effectively unused on this kernel.
- Make the patch structurally correct for the real arm64 XNU syscall ABI so it can be dry-run validated without relying on guessed stack contracts.
Verified PCC 26.1 Facts
sysent[439] on the loaded PCC 26.1 research kernel
- IDA function
sub_FFFFFE00081279E4is the arm64 Unix syscall dispatcher (unix_syscallsemantics confirmed by XNU source and call shape). - It computes the syscall-table base as
off_FFFFFE000773F858and indexes entries asbase + code * 0x18. - Therefore
sysent[439]is at:- VA
0xFFFFFE0007742180 - file offset
0x0073E180
- VA
- Unpatched entry contents on PCC 26.1:
sy_call = 0xFFFFFE0008077978sy_arg_munge32 = 0xFFFFFE0007C6AC4Csy_return_type = 1sy_narg = 3sy_arg_bytes = 0x000C
Raw entry dump
- 24-byte
sysent[439]dump as observed in IDA / local decode:- qword
[+0x00]:0xFFFFFE0008077978 - qword
[+0x08]:0xFFFFFE0007C6AC4C - dword
[+0x10]:0x00000001 - half
[+0x14]:0x0003 - half
[+0x16]:0x000C
- qword
- Same entry in 32-bit little-endian words:
08077978 fffffe00 07c6ac4c fffffe00 00000001 000c0003
What syscall 439 currently does here
0xFFFFFE0008077978disassembles to:MOV W0, #0x2DRET
0x2Dis45decimal, i.e.ENOTSUP.- So on this PCC 26.1 research kernel,
SYS_kas_infois effectively a stubbed-outENOTSUPsyscall target, which makes it a good hook point.
Verified dispatcher ABI
- In
sub_FFFFFE00081279E4, the handler call sequence is:LDR X8, [X22]MOV X0, X21MOV X1, X19MOV X2, X24MOV X17, #0xBCADBLRAA X8, X17
- Derived state at the call:
X21 = struct proc *X19 = &uthread->uu_arg[0]X24 = &uthread->uu_rval[0]
- So the real handler ABI is:
x0 = struct proc *x1 = &uthread->uu_arg[0]x2 = &uthread->uu_rval[0]
XNU Cross-Check
research/reference/xnu/bsd/sys/sysent.hdefinessy_call_tasint32_t sy_call(struct proc *, void *, int *).research/reference/xnu/bsd/dev/arm/systemcalls.cshowsunix_syscall()calling(*callp->sy_call)(proc, &uthread->uu_arg[0], &uthread->uu_rval[0]).- arm64
unix_syscallonly accepts up to 8 syscall argument slots. research/reference/xnu/bsd/sys/user.hshowsuu_rvalisint uu_rval[2], so the natural 64-bit return path is_SYSCALL_RET_UINT64_T, which packs one 64-bit value across those two 32-bit cells.
Why The Historical Design Was Wrong
Old idea
- Historical notes described a cave that:
- recovered a pointer from
[sp,#0x40] - treated that pointer as
{ target, arg0..arg9, out_regs... } - called the target with
BLR - wrote many registers back to the same buffer
- returned
0
- recovered a pointer from
Problems
- The syscall ABI never passes a userspace request buffer via
[sp,#0x40]. - arm64 XNU does not provide a 10-argument Unix syscall ABI.
uu_argonly holds 8 qwords, so the old cave over-read / over-wrote beyond the copied syscall arguments.- The old design bypassed the real syscall return channel (
retval/uu_rval) and therefore did not actually match howunix_syscall()returns results to userspace.
Rebuilt Patch Design
Practical decision
- A literal direct-call
kcall10is not ABI-compatible with this kernel's Unix syscall path. - The rebuilt patch therefore keeps the historical hook point but redefines the request format into an ABI-correct reduced form:
- target function pointer
- 7 direct arguments
- 64-bit X0 return value
- This keeps the patch usable as a kernel-call bootstrap while staying within the real syscall ABI.
New uap layout
The rebuilt patcher uses sy_narg = 8, with x1 pointing at a copied 8-qword argument block:
struct kcall10_uap_rebuilt {
uint64_t target;
uint64_t arg0;
uint64_t arg1;
uint64_t arg2;
uint64_t arg3;
uint64_t arg4;
uint64_t arg5;
uint64_t arg6;
};
New semantics
uap[0]= target function pointeruap[1..7]= arguments loaded intox0..x6x7is forced to zero in the cave- target return
x0is stored toretval sysent[439].sy_return_typeis set to_SYSCALL_RET_UINT64_T- userspace receives one 64-bit return value in
x0
Python Implementation
The dedicated patcher file is now:
scripts/patchers/kernel_jb_patch_kcall10.py
What it now does
- Finds the real
sysenttable by scanning backward from a decoded_nosysentry. - Locates a reusable 8-argument
sy_arg_munge32helper from the live table and now requires that the decoded helper target be unique across all matching sysent rows. - Allocates an executable cave sized to the emitted blob instead of relying on a fixed large reservation.
- Emits an ABI-correct cave that:
- validates
uap,retval, andtarget - loads
target + 7 argsfromx1 - performs
BLR X16 - stores
X0tox2 - returns
0on success orEINVALon malformed input
- validates
- Rewrites
sysent[439]to point at the cave. - Rewrites
sysent[439].sy_arg_munge32to an 8-argument helper. - Rewrites metadata to:
sy_return_type = 7sy_narg = 8sy_arg_bytes = 0x20
Expected Emitted Patch Shape
The rebuilt patch should emit exactly four writes:
- Code cave blob in
__TEXT_EXEC sysent[439].sy_call = cavesysent[439].sy_arg_munge32 = 8-arg mungersysent[439].sy_return_type / sy_narg / sy_arg_bytes
Static Acceptance Criteria
The rebuilt patch is considered structurally correct if all of the following hold:
sysent[439]still decodes as a valid auth-rebase entry after patching.sy_narg == 8andsy_arg_bytes == 0x20.- No cave instruction reads from guessed caller-frame offsets like
[sp,#0x40]to recover user arguments. - The cave consumes the real syscall handler ABI:
(proc, uap, retval). - The cave returns the 64-bit primary result through
retvaland_SYSCALL_RET_UINT64_T. - The cave does not read beyond the 8 copied syscall qwords.
Risks
- Arbitrary kernel call surface: this patch intentionally creates a direct kernel-call primitive from userspace; any reachable caller with sufficient privilege can invoke sensitive kernel routines with attacker-controlled arguments.
- Target-function safety: the cave does not validate the semantic suitability of the target function. Calling a function with the wrong prototype, wrong locking expectations, or wrong context can panic or corrupt kernel state.
- Argument-width limit: this rebuilt version is ABI-correct but only supports
target + 7 args -> uint64 x0. Workflows that silently assume the old pseudo-10-arg contract will misbehave until userspace is updated. - Return-value limit: only primary
x0is surfaced through the syscall return path. Any target that needs structured outputs, out-pointers, or multiple architecturally relevant return registers still needs a higher-level descriptor / copyout design. - PAC / branch-context coupling: the
sy_callhook itself preserves the expected authenticated-call shape, but the target function call inside the cave is a plainblr x16. If the chosen target relies on a different authenticated entry expectation or unusual calling context, behavior may still be unsafe. - Scheduler impact: re-enabling this patch in the default JB list means future aggregate dry-runs and restore tests now include it. Any regression observed after this point must consider
patch_kcall10as part of the active set.
Current Limits
- This rebuilt patch is ABI-correct, but it is no longer a literal “10 direct argument” trampoline.
- It provides a reduced-form direct-call primitive:
target + 7 args -> uint64 x0. - If a future design needs more arguments or structured output, it should move to a descriptor +
copyin/copyoutmodel rather than trying to extend the raw syscall ABI.
Validation Plan
- Keep work scoped to this single patch.
- Run a dedicated dry-run against
ipsws/PCC-CloudOS-26.1-23B85/kernelcache.research.vphone600. - Verify the emitted cave disassembly matches the rebuilt design.
- Verify the three
sysent[439]field writes match the intended targets and metadata. - Stop at dry-run validation; do not escalate to full firmware build in this step.
Dry-Run Validation (2026-03-06)
Target image:
ipsws/PCC-CloudOS-26.1-23B85/kernelcache.research.vphone600
Result:
method_return = Truepatch_count = 4
Emitted writes:
0x00AB1720— cave blob, size0x6C0x0073E180—sysent[439].sy_call = cave0x0073E188—sysent[439].sy_arg_munge32 = 8-arg helper0x0073E190—sy_return_type = 7,sy_narg = 8,sy_arg_bytes = 0x20
Exact emitted bytes:
- cave @
0x00AB1720:7f2303d5ffc300d1f55b00a9f35301a9fd7b02a9fd830091d3028052f40301aaf50302aa940100b4750100b4900240f9300100b4808640a9828e41a9849642a9861e40f9e7031faa00023fd6a00200f913008052e003132af55b40a9f35341a9fd7b42a9ffc30091ff0f5fd6
sysent[439].sy_call@0x0073E180:2017ab00adbc1080
sysent[439].sy_arg_munge32@0x0073E188:286dc600be2a2080
- metadata @
0x0073E190:0700000008002000
Decoded post-patch fields:
sy_calldecodes to cave file offset0x00AB1720sy_arg_munge32decodes to helper file offset0x00C66D28(chosen only after confirming the 8-arg helper target is unique across matching sysent rows)sy_return_type = 7sy_narg = 8sy_arg_bytes = 0x20
Cave disassembly summary:
- prologue:
pacibsp, 0x30-byte stack frame, savesx19-x22,x29,x30 - validation: reject null
uap, nullretval, nulltargetwithEINVAL - load path: reads target from
[x20], args from[x20+0x8 .. +0x38] - call path:
blr x16withx0..x6populated andx7 = 0 - return path:
str x0, [x21], move status intow0, restore callee-saved registers,retab