TXM selector 24 CMS gate — the iPhone 17,3 / 27.0.1 (24A446) first-boot panic
Historical investigation. The forced type-10 pre-check patch described below has been removed in favor of native signature classification. Host tests cover the original rejection paths; the replacement has iOS 27.1 remap results and tester-reported startup success. The boot results below apply to the former implementation, not a retest of the same 27.0.1 pairing.
Investigated 2026-10-04, after a vm create that defaulted to
iPhone17,3 27.0.1 (24A446) restored and CFW-installed cleanly, then panicked
on first boot:
The VM (unlocktest-iphone) was deleted before this analysis; everything
below was rebuilt statically from the IPSWs themselves (members fetched by
HTTP range from the CDN zips; artifacts kept under /tmp/txm-*.bin).
Which TXM actually boots
mergeCloudOS (VPhoneFirmwarePreparer.swift) copies cloudOS
Firmware/*.im4p into the iPhone restore tree with overwrite, so
txm.iphoneos.research.im4p from cloudOS 26.4-23E5207q
(TrustedExecutionMonitor_Guarded-187.100.3, 442400 bytes) replaces the
iPhone IPSW's own before the patcher and restore ever see it:
Through 26.x the two sides shipped near-identical TXMs, so the override was
invisible and harmless. iOS 27 moved the TXM a full version (+115 KB) while
the VM kept booting the 26.4-era 187.100.3. The 12 dev patches apply to (and
were verified against) 187.100.3. The VM's SPTM is also cloudOS's
(sptm.vresearch1.release.im4p); the iPhone IPSW only ships sptm.t8140
for its own hardware. TXM and SPTM in the guest are a matched 26.4 pair.
Offsets below are raw file offsets, given for 187.100.3 (what boots)
with 217.0.2 in parentheses where useful. 187.100.3 __TEXT_EXEC: file
offset 0x1c000; 217.0.2: file offset 0x2c000, vmaddr
0xfffffff017030000 (neither is the 26.3 layout in txm_jb_patches.md).
Decoding the panic value
The kernel-side log prints the selector number followed by the low, middle
and high bytes of TXM's 32-bit error return. 0x91 | 0x24 | 1 is
0x0001_2491.
The selector-24 ladder (identical shape in both TXM versions)
sub_31F74 (217.0.2: sub_43CB8) — multi-step validator
The pre-check walk (sub_30BAC) is the 217/187 equivalent of the 26.x
pre-check chain (library validation, runtime flag, jit entitlement, team
id, SRD, extended research, hash type). The patched check_hash_flags
(187.100.3: near 0x31a84, early-returned PASS by
txm-boot-selector24_bypass) is one step inside it.
sub_30774 (217.0.2: sub_424A8) — the CMS gate that fired
If the wrapper is found, the function locates the CodeDirectory
(0xfade0c02, searched as magic + 0x101), parses both, and verifies the
manifest cdhash (≤0x40-byte hash at ctx+0x40) — the full "the CMS says who
signed this" step. The exit packs the printed error:
mid=(w8&0xff)<<8 (0x24), low=w21&0xff (0x91), high=w22 (0x10000 → 1).
0x12491 means: no CSMAGIC_BLOBWRAPPER blob in the signature data that
selector 24 was handed.
Why our launchd dies there
patchMachO re-signs /sbin/launchd (jetsam guard patch + /vh injection,
system-launchd-boot-jetsam_panic_guard_bypass) with VPhoneSigner at its
default style: .ldid:
(VPhoneSign/Signing/VPhoneSigner.swift.) So the re-signed launchd carries
no CMS wrapper and CodeDirectory flags = 0: flags bit1 is clear (the
ad-hoc branch is not taken), and the CMS branch finds no 0xfade0b01
anywhere → 0x12491 → init SIGKILLed. None of the 12 applied TXM patches
touches this ladder — hence a clean patch log with no warnings.
What is and is not the trigger (elimination, 2026-10-04)
The failing machine ran iPhone-class iOS 27.0.1 with local bundle
2.4.0-local.ed71da3b (installed 2026-10-04 00:26, mid audio-branch WIP).
Every candidate signed artifact in the boot path was then compared between
the failing and passing combinations:
Known boots, for contrast:
Note the launchd result kills the earlier "27.0.1 launchd data trips a
policy" theory: the binary the gate rejected — if it was launchd at all — is
byte-for-byte what boots on 27.0. Whatever flipped the sub_30BAC pre-check
into the CMS fallback is either (a) something in that WIP bundle's install
output (the audio branch was mid-refactor at 00:26; today's bundles carry the
fixes from 8fa502a/fa50d48/62ee326 and boot), or (b) a 27.0.1
system-volume input outside launchd/cache/DSC (restore ramdisk, Preboot
content), or (c) TXM runtime policy state that boot handed it differently.
The one discriminating experiment: iPhone 17,3 + 27.0.1 + current bundle —
vphone-launchpad-cli vm create t271 --iphone-source ~/.vphone/ipsws/iPhone17_3_27.0.1_24A446_Restore-1c2c1e8da8de.ipsw
(IPSW already cached). Boots ⇒ the WIP bundle was the trigger; panics
identically ⇒ 27.0.1-specific input, pursue the fixes below.
Confirming the remaining link (reveal procedure)
- Download
043-70113-711.dmg.aea(24A446 rootfs) and043-70113-702.dmg.aea(24A435) from the two iPhone IPSWs (zip members; the rest of the 12 GB is not needed). vphone-cli fw aea-key <dmg.aea>→aea decrypt -key-value …(documented flow; it worked on both 24A435 volumes before).- Attach the decrypted APFS images, pull
sbin/launchdfrom each (and from the iPad 16,1 27.0.1 IPSW as the passing 27.0.1 control). - Compare, in order of likelihood: embedded entitlements (plist and DER slots), CodeDirectory version/hashType/flags/identifier, superblob slot list (magics and order).
- Reproduce by re-running the CFW launchd staging on all three and diffing
VPhoneSigneroutput.
Round 3 (2026-10-04 evening): every input-side artifact is now identical
The 0x32202 boot was compared against patchtest-iphone (iPhone-class, iOS
27.0, boots, driven by the parallel session) artifact by artifact:
The signature shape is therefore not what the pre-check keys on (a flags=0 ldid launchd passes on 27.0; both shapes die on 27.0.1). With launchd, device tree, dyld cache, TXM, kernel, SEP and SPTM all eliminated, what remains is per-build data the restore personalizes into the guest's trust chain — the trust cache content itself (27.0.1's TCTF/magazine format or its personalization metadata vs what the fixed 26.4 kernel/TXM can admit). Where to go next:
- Ask the restore side where trust caches land:
VPhoneRestore/ idevicerestore personalize*.dmg.trustcache— trace what it writes and what the 26.4 kernel expects to find at boot. - Reverse the three policy callbacks behind
sub_30BAC's walk in TXM 187.100.3 (selector0x7e51, table slots+0x20/+0x18) — the definitive answer to which input flips. - Empirical discriminator: boot 27.0.1 with an unpatched Apple launchd
(swap
sbin/launchd.bakback in through the CFW mount). If the original — whose cdhash is in Apple's cache — also dies, the trust caches never load at all on 27.0.1 and the ladder is unreachable for everyone; if it boots, the caches load and the policies specifically reject re-signed hashes on 27.0.1.
Round 4 (2026-10-04 night): the definitive experiment — it is not the signing
system-launchd-boot-jetsam_panic_guard_bypass was blocked through
PatchSelection.plist (BlockedPatches, honored by fw patch with a
boot-essential warning), the tree re-prepared and CFW re-installed, so the
guest booted the pristine Apple launchd — ad-hoc flags=0x2 straight from
the IPSW, its cdhash in Apple's static trust cache, no /vh injection, no
re-signing at all.
It died identically: TXM [Error]: CodeSignature: selector: 24 | 0x02 | 0x22 | 3 (0x32202) → unexpected SIGKILL of init.
That closes the case at this level:
- The re-signed binaries were never the problem. On the iPhone17,3 27.0.1 guest, TXM's selector-24 admission rejects every binary — including Apple's own, trust-cache-listed launchd — because whatever its pre-check policies and the ad-hoc branch's callback consult (the trust caches) is not loaded at boot on 27.0.1, while the identical 27.0 flow loads it (booting even ldid-shaped re-signed binaries).
- The StaticTrustCache files themselves are format-identical between builds
(same size 91441, same TCTF structure, only hash values differ), and the
restore delivers them as personalized TSS assets (
StaticTrustCacheinrestore.c's asset list). The failing console'smagazine[…]: failed to read nonce slot data: 2(ENOENT — a nonce slot missing) vs 27.0's errno 13/6 points at the personalization/nonce-slot handshake differing for 27.0.1's images against the fixed 26.4 SEP/TXM. - Open wrinkle: the iPad16,1 27.0.1 guest booted today, so either its restore personalized differently or the iPad tree configures TXM policies to tolerate an empty magazine. Worth one look when fixing.
The fix surface is the restore's TSS/personalization of 27.0.1's trust
caches (nonce slot selection in VPhoneRestore/tss code), or the
kernel/TXM patch route (force-pass the sub_30BAC pre-check walk, which
covers every branch of the ladder at once).
The patch: txm-boot-precheck_admission (2026-10-04) — VERIFIED, 27.0.1 boots
Machine t271x (iPhone17,3 + 27.0.1 + cloudOS 26.4 + the patch, bundle
2.5.0-local.94f7c22c): restore, CFW install, first boot — running,
panicked: false, no selector-24 line in the console, and vphoned answers
device.info live. The acceptance bar is met. (Note for retesting: the
boot-chain TXM is flashed at restore time — a machine restored before the
patch keeps booting the old TXM until re-restored.)
TXMDevPatcher.patchPrecheckForcePass() forces the pre-check walk
(sub_30BAC, 187.100.3 offsets; sub_428F0 in 217.0.2) to its PASS exit, so
the selector-24 caller accepts at the top of the ladder and none of the
fallback branches — ad-hoc, CMS gate, third fallback — ever run.
Reveal procedure (how the site was found and how to re-find it on a new TXM):
- Decompress
Firmware/txm.iphoneos.research.im4pfrom the merged restore tree (it is cloudOS 26.4's 187.100.3; the iPhone IPSW's copy is overwritten bymergeCloudOS— see above). - Scan for
mov x17, #0x7e51(movz encoding0xD28FCA31) followed byblraa x8, x17. On 187.100.3 this hits three times; only the pre-check walk's function also contains the post-indexedldr x22, [x20], #0x40policy-table walk before the hit (the other two hits share an unrelated function at0x32d78). - Walk back to the
pacibspprologue; the two instructions after it aremov x19, x1 ; mov x20, x0— the patch overwrites the four instructions that follow withmov w8, #0xa ; strb w8, [x19] ; mov w0, #0x90 ; b <epilogue>(epilogue = theretab's precedingldp x29, x30).0x90is the walk's own PASS status (byte 1 clear);0xais the validation-type byte the table-tolerated path writes to the out param.
Validation: constant words are capstone round-trip verified and frozen in
ARM64EncoderTests; the anchor pair resolves to exactly one function on
187.100.3; the boot test on t271 (iPhone17,3 + 27.0.1 + the patched bundle)
is the acceptance bar. The patch is declared txm-boot-precheck_admission
(bootchain set, iOSBase: .major(27), bootEssential) — on 27.0 the walk
already admits everything, so the patch changes bytes but not behavior.
Fix options and what the 2026-10-04 experiments proved
- Reproduction done (machine
t271, iPhone17,3 + 27.0.1 + release 2.5.0): identical0x12491panic — the trigger is 27.0.1-specific, the WIP-bundle theory is dead. (An iPhone-class 27.0 guest booted the same day on the same Mac.) style: .appleAdHocre-signing — implemented and tested. All threeVPhoneSigner.signcall sites inVPhoneCustomFirmwareInstaller.swiftnow passstyle: .appleAdHoc. Deployed throughvm set-bundle t271 2.5.0-local.4f3be451+cfw install(note:vm create --from installCFW --bundle …does not rebind the machine — verifylaunchpad.jsonand the on-diskflags=0x2before believing a test). Result: the on-disk launchd carriesflags=0x2(adhoc), the0x12491CMS-gate error is gone (the ladder analysis held), but init still dies — now withselector: 24 | 0x02 | 0x22 | 3(0x32202), the error after the whole ladder is exhausted: pre-check walk → ad-hoc branchsub_30B1C→ third fallbacksub_30A78all rejected, and the table tolerance bytes are clear. The signing change is correct but not sufficient; it is not yet regression-tested on a booting guest (patchtest-iphone is the candidate).- The layer under the ladder: trust caches never load in the 27.0.1
guest. The failing console uniquely shows, before the kill:
TXM [Error]: Errno: selector: 45 | 78,AppleImage4: failed to set boot uuid in supervisor: 78,magazine[cptx]: failed to get nonce: 13,magazine[c1bt]: failed to get nonce: 6, andis_root_hash_authentication_required: disk1s1 Root Volume, root hash authentication is required. Every passing machine's console (patchtest-iphone 27.0, both iPads 26.6.2) has none of these and instead shows a successful runtimeAppleMobileFileIntegrityUserClient::loadTrustCache … requesting a trust cache load. With the trust-cache magazine empty in TXM, the selector-24 pre-check policies have nothing to admit against, which is what pushes the re-signed launchd into the ladder at all. Why the 27.0.1 magazine / nonce path fails against the fixed 26.4 SEP/SPTM/TXM (format change? new nonce protocol?) is the open question — that is where a real fix lives, not in the signature shape. - A new TXM dev patch forcing the
sub_30774wrapper-not-found exit to pass is now the wrong lever: the ladder has three more rejection points after it (0x32202 proves it). A patch that force-passes the pre-check walk would cover all of them at once, but it is a policy-grade change (seeSkills/authoring-patch-sets/SKILL.md). - Stop discarding the iPhone's TXM: exclude
txm.*from the cloudOSFirmware/*.im4poverwrite so the guest boots the TXM contemporary with its userland (217.0.2 on iOS 27.x). Not a cloudOS version bump (none is possible; nothing after26.4-23E5207qcarriesvphone600ap). Risk: the booted TXM must pair with cloudOS 26.4'ssptm.vresearch1and the 26.4 kernel's selector call convention; needs an empirical boot.