Prefix research patch comparison doc and normalize root markdown names Rename research root markdown files to scoped topic names
8.3 KiB
JB Mount Failure Investigation (2026-03-04)
Symptom
make setup_machine JB=1reachedcfw_install_jband failed at:Failed to mount /dev/disk1s1 at /mnt1 (opts=rw).
Runtime Evidence (Normal Boot)
From make boot serial log:
- APFS mount tasks fail with permission errors:
mount_apfs: volume could not be mounted: Operation not permittedmount: /private/xarts failed with 77mount: /private/preboot failed with 77- launchd panics:
boot task failure: mount-phase-1 - exited due to exit(77)
- Ignition/boot path shows entitlement-like failure:
handle_get_dev_by_role:13101: disk1s1 This operation needs entitlement
This indicates failure in APFS role-based device lookup during early boot mount tasks.
Runtime Evidence (DEV Control Run, 2026-03-04)
From a separate fw_patch_dev + cfw_install_dev boot log (not JB):
mount-phase-1succeeded for xART:disk1s3 mount-complete volume xART/dev/disk1s3 on /private/xarts ...
- launch progressed to:
data-protectionfinish-obliterationdetect-installed-rootsmount-phase-2
Interpretation: APFS boot-mount path can work on this build/kernel family after recent APFS gate changes. This does not prove JB flow is fixed; it is a control signal showing the kernel-side path is not universally broken.
Flow Separation (Critical)
- The successful
xART mount-complete/mount-phase-2log is from DEV pipeline:fw_patch_dev+cfw_install_dev
- JB pipeline remains:
fw_patch_jb+cfw_install_jb
cfw_install_jbdoes not callcfw_install_dev; it runs basecfw_install.shfirst, then JB-only phases.
Kernel Artifact Checks
1) Ramdisk kernel identity
vm/Ramdisk/krnl.img4payload hash was byte-identical to:vm/iPhone17,3_26.1_23B85_Restore/kernelcache.research.vphone600
So ramdisk boot was using the same restore kernel payload (no accidental file mismatch in ramdisk_build).
2) Patchability state (current VM kernel)
On vm/iPhone17,3_26.1_23B85_Restore/kernelcache.research.vphone600:
- Base APFS patches:
patch_apfs_vfsop_mount_cmp-> not patchable (already applied)patch_apfs_mount_upgrade_checks-> not patchable (already applied)
- Key JB patches:
patch_mac_mount-> patchablepatch_dounmount-> patchablepatch_kcall10-> patchable
Interpretation: kernel is base-patched, but critical JB mount/syscall extensions are still missing.
3) Reference hash comparison
- CloudOS source
kernelcache.research.vphone600payload:b6846048f3a60eab5f360fcc0f3dcb5198aa0476c86fb06eb42f6267cdbfcae0
- VM restore kernel payload:
b0523ff40c8a08626549a33d89520cca616672121e762450c654f963f65536a0
So restore kernel is modified vs source, but not fully JB-complete.
IDA Deep-Dive (APFS mount-phase-1 path)
1) Failing function identified
- APFS function:
sub_FFFFFE000948EB10(log name:handle_get_dev_by_role) - Trigger string in function:
"%s:%d: %s This operation needs entitlement\\n"(line 13101)
- Caller xref:
sub_FFFFFE000947CFE4dispatches tosub_FFFFFE000948EB10
2) Gate logic at failure site
The deny path is reached if either check fails:
- Context gate:
BL sub_FFFFFE0007CCB994CBZ X0, deny
- "Entitlement" gate (APFS role lookup privilege gate):
ADRL X1, "com.apple.apfs.get-dev-by-role"BL sub_FFFFFE000940CFC8CBZ W0, deny
- Secondary role-path gate (role == 2 volume-group path):
BL sub_FFFFFE000817C240CBZ W0, deny(to line 13115 block)
The deny block logs line 13101 and returns failure.
3) Patch sites (current vphone600 kernelcache)
- File offsets:
0x0248AB50— context gate branch (CBZ X0, deny)0x0248AB64— role-lookup privilege gate (CBZ W0, deny)0x0248AC24— secondary role==2 deny branch (CBZ W0, deny)
- All three patched to
NOPin the additive APFS patch.
4) Additional APFS EPERM(1) return paths in apfs_vfsop_mount
Function:
sub_FFFFFE0009478848(apfs_vfsop_mount)
Observed EPERM-relevant deny blocks:
- Root-mount privilege deny:
- log string:
"%s:%d: not allowed to mount as root\n" - xref site:
0xFFFFFE000947905C - error return: sets
W25 = 1
- log string:
- Verification-mount privilege deny:
- log string:
"%s:%d: not allowed to do a verification mount of %s (is_suser %s ; uid %d)\n" - xref site:
0xFFFFFE0009479CA0 - error return: sets
W25 = 1
- log string:
Important relation to existing Patch 13:
- At
0xFFFFFE0009479044(same function), current code isCMP X0, X0(patched form), which forces the followingB.EQpath and should bypass one root privilege check in this region. - Therefore, if JB still reports
mount_apfs ... Operation not permitted, remaining EPERM candidates include other deny branches (including the verification-mount gate path above), not onlyhandle_get_dev_by_role.
Root Cause (Updated, Two-Stage)
Stage 1 (confirmed and mitigated):
- APFS
handle_get_dev_by_roleentitlement/role deny gates were a concrete mount-phase-1 blocker. - Additive patch now NOPs all three relevant deny branches.
Stage 2 (still under investigation, JB-only):
- DEV control run can pass
mount-phase-1/mount-phase-2. - JB failures must be analyzed with JB-only artifacts/logs and likely involve JB-only deltas (launchd dylib injection, BaseBin hooks, or JB preboot/bootstrap interaction), in addition to any remaining kernel checks.
Mitigation Implemented
A) Ramdisk kernel split (updated implementation)
scripts/fw_patch_jb.py- no longer creates a ramdisk snapshot file
scripts/ramdisk_build.py- derives ramdisk kernel source internally:
- uses legacy
kernelcache.research.vphone600.ramdiskif present - otherwise derives from pristine CloudOS
kernelcache.research.vphone600underipsws/*CloudOS*/using baseKernelPatcher
- uses legacy
- builds:
Ramdisk/krnl.ramdisk.img4from derived/base sourceRamdisk/krnl.img4from post-JB restore kernel
- derives ramdisk kernel source internally:
scripts/ramdisk_send.sh- prefers
krnl.ramdisk.img4when present.
- prefers
B) Additive APFS boot-mount gate bypass (new)
- Added new base kernel patch method:
KernelPatchApfsMountMixin.patch_apfs_get_dev_by_role_entitlement()
- Added to base kernel patch sequence in
scripts/patchers/kernel.py. - Behavior:
- NOPs three deny branches in
handle_get_dev_by_role - does not modify existing filesystem patches (APFS snapshot/seal/graft/mount/sandbox hooks remain unchanged).
- NOPs three deny branches in
C) JB-only differential identified (for next isolation)
Compared with DEV flow, JB adds unique early-boot risk factors:
- launchd binary gets
LC_LOAD_DYLIBinjection for/cores/launchdhook.dylib launchdhook.dylib/BaseBin environment strings include:JB_ROOT_PATHJB_TWEAKLOADER_PATH- explicit launchdhook startup logs (
hello/bye)
- procursus/bootstrap content is written under preboot hash path (
/mnt5/<hash>/jb-vphone)
These do not prove causality yet, but they are the primary JB-only candidates after Stage-1 APFS gate mitigation.
Next Validation
- Kernel/JB isolation run (requested):
make fw_patch_jbmake ramdisk_buildmake ramdisk_send- run
cfw_install_dev(not JB) on this JB-patched firmware baseline
- Compare normal boot result:
- If
mount-phase-1/2succeeds: strong evidence issue is in JB-only userspace phases. - If it still fails with
EPERM: continue kernel/APFS deny-path tracing.
- If
- If step 2 succeeds, add back JB phases incrementally:
- first JB-1 (launchd inject + jetsam patch)
- then JB-2 (preboot bootstrap)
- then JB-3 (BaseBin hooks) and capture first regression point.
2026-03-05 Follow-up (Data-Protection / SEP UserClient MACF)
A later failure mode moved past mount-phase and failed in data-protection:
IOUC AppleSEPUserClient failed MACF ... seputilBoot task failed: data-protection - exited due to exit(60)
This was traced to unpatched IOKit MAC policy hook range (ops[201..210]) in
the sandbox extended hook set. Mitigation and patch details are documented in:
research/boot_data_protection_seputil_macf_investigation.md
Follow-up (2026-03-06):
- Even after
ops[201..210]extension, runtime still showed:IOUC AppleAPFSUserClient failed MACF ...IOUC AppleSEPUserClient failed MACF ...
- A second-stage mitigation was added:
patch_iouc_failed_macf(central IOUC MACF gate low-risk early return).