fix(build): gate SCSI HBA behind opt-in build flag — default build can boot-panic at cold boot#55
Merged
Conversation
The ASFWSCSIControllerService personality instantiates a kernel-side IOUserSCSIParallelInterfaceController as soon as the FireWire card matches at boot. On machines where AMFI enforces entitlements, the ad-hoc-signed dext carrying the restricted scsicontroller entitlement is killed at launch, and the orphaned kernel stub panics the kernel about a minute after boot — a boot loop, with no device attached. Default build now ships neither the personality nor the entitlement: - ASFW_ENABLE_SCSI=NO (pbxproj) selects the entitlements file and preprocesses the SCSI personality out of Info.plist - ./build.sh --scsi opts in (xcodebuild ASFW_ENABLE_SCSI=YES) - sign.sh picks the matching entitlements file by detecting the personality in the built dext, so signature and plist never diverge Verified both flag states: built artifacts carry personality and scsicontroller entitlement together or not at all.
The README and build.sh attributed the boot panic solely to the
AMFI-kill path ("only on a machine that runs with SIP disabled"),
implying SIP-off machines are safe. They are not: with the dext
running, the HBA reports target 0 present unconditionally and the
probe INQUIRY is held with no deadline waiting for an SBP-2 login
that never arrives when no SBP-2 device is on the bus — the stalled
target registration trips the same 60 s registry busy-timeout panic
(IOService.cpp:5986) regardless of SIP state.
Document both paths, warn that --scsi builds are not cold-boot-safe
without a powered-on SBP-2 device until the HBA-side fix (create the
target at SBP-2 login instead of boot) lands, and note that a stalled
probe on a running system can still panic later on adapter unplug or
extension teardown.
9 tasks
There was a problem hiding this comment.
Pull request overview
This PR mitigates a cold-boot kernel panic risk by making the SCSI HBA (SBP-2 bridging via SCSIControllerDriverKit) opt-in at build/sign time, so default builds ship audio-only without the SCSI personality or restricted scsicontroller entitlement.
Changes:
- Adds an
ASFW_ENABLE_SCSIbuild setting (defaultNO) to gate theASFWSCSIControllerServicepersonality via Info.plist preprocessing and to select the correct entitlement set. - Extends
build.shwith--scsito passASFW_ENABLE_SCSI=YEStoxcodebuild. - Updates
sign.shto auto-detect whether the SCSI personality is present in the built.dextand sign with matching entitlements; documents the opt-in and recovery steps in the README.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| sign.sh | Detects SCSI personality in the built dext and selects matching entitlements to prevent entitlement/personality mismatch. |
| README.md | Documents SCSI HBA opt-in, panic mechanisms, cold-boot warning, and recovery/uninstall guidance. |
| build.sh | Adds --scsi flag that enables the SCSI packaging path by passing ASFW_ENABLE_SCSI=YES to Xcode builds. |
| ASFWDriver/Info.plist | Wraps the SCSI controller personality in #if ASFW_ENABLE_SCSI so it’s excluded by default. |
| ASFWDriver/ASFWDriver+SCSI.entitlements | Introduces a dedicated entitlement set that includes com.apple.developer.driverkit.family.scsicontroller. |
| ASFWDriver/ASFWDriver.entitlements | Removes the restricted scsicontroller entitlement from the default (audio-only) entitlement set. |
| ASFW.xcodeproj/project.pbxproj | Wires ASFW_ENABLE_SCSI to entitlement selection and Info.plist preprocessing/definitions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
Since #46 merged, a default build of main can kernel-panic a machine that cold-boots with a FireWire OHCI controller attached and no SBP-2 device present — a boot panic loop, ~60–80 s after power-on, no device plugged in. A contributor hit this in the wild (#54). This PR makes the SCSI HBA opt-in at build time (
./build.sh --scsi/ASFW_ENABLE_SCSI=YES), so the default artifact carries neither theASFWSCSIControllerServicepersonality nor the restrictedscsicontrollerentitlement.The panic
IOKit registry busy-timeout at boot: the FW643 PCI nub never went quiet within watchdogd's 60 s boot-quiesce window.
Root cause
Two independent mechanisms converge on this exact panic signature, and both start from the same trigger: the
ASFWSCSIControllerServicepersonality matches the FW643 PCI nub at boot and the kernel instantiatesIOUserSCSIParallelInterfaceController.Mechanism 1 — stranded probe (dext runs fine). The chain is fully confirmed in the code:
UserTargetPresentForID(0)answers true unconditionally → the framework auto-creates SCSI target 0.fTimeoutInMilliSecis 0 (infinite).ASFWSCSIController.cpp,TryHoldInquiry; the storedtimeoutMsis only used on replay). The only paths that release a held INQUIRY are SBP-2 login,Stop(), and a task abort — none fires here.pci11c1,5901never drains; watchdogd panics the boot at 60 s.This mechanism is independent of SIP/AMFI state, and the same
IOService.cpp:5986signature was observed twice during HBA development with a live, running dext (including anIOSCSITargetDevice+IOThunderboltPortbusy chain matching the reporter's TB-adapter topology).Mechanism 2 — AMFI kill (dext never runs). The ad-hoc signature carrying the restricted
scsicontrollerentitlement gets the dext killed at launch on an AMFI-enforcing machine. Since everything runs in one process (IOUserServerOneProcess), that takes the audio driver down too, and the orphaned kernel stub strands the same busy chain.The panic report in #54 does not discriminate between the two — both end in the identical watchdogd busy-timeout. Mechanism 1 is the better-supported theory (code-confirmed chain; the reporter ran pre-#46 ad-hoc builds carrying equally-restricted entitlements without issue, which argues against a suddenly-stricter AMFI). A cheap discriminator, if the reporter can run it after a panicking boot:
log show --boot -1 --predicate 'eventMessage CONTAINS "[SCSIHBA]"' --info --debug— any output means the dext launched, ruling out the AMFI path. Either way, this PR removes both mechanisms for default builds: no personality → no kernel stub, no restricted entitlement → nothing for AMFI to reject.What this PR does
ASFW_ENABLE_SCSIbuild setting, defaultNO, on the dext target (both configs):ASFWDriver.entitlements(audio-only, default) vsASFWDriver+SCSI.entitlementsASFWSCSIControllerServicepersonality out of Info.plist (INFOPLIST_PREPROCESS+-traditional)./build.sh --scsipassesASFW_ENABLE_SCSI=YESsign.shauto-detects the personality in the built dext and picks the matching entitlements file, so signature and Info.plist cannot diverge--scsibuilds are not cold-boot-safe without a powered-on SBP-2 device (until the HBA-side fix lands), panic-loop recovery steps, and a tester warning to uninstall the extension before re-enabling SIPThe entitlement + personality are gated together deliberately: the personality without the entitlement leaves an orphaned kernel stub (mechanism 2's path), and the entitlement without the personality gets the whole one-process dext killed by AMFI on enforcing machines, taking audio down with it.
All SCSI/SBP-2 code still compiles in every build — only packaging is gated. Scanner users opt in with one flag.
Verification
Built both flag states via plain
xcodebuildand viabuild.sh+sign.sh, and inspected the artifacts:--scsi/ASFW_ENABLE_SCSI=YESplutil -lintclean, variable substitution intact,sign.shauto-detect exercised end-to-end in both states. The reporter's independently-made strip build (same shape as the default artifact) boots clean on the affected machine.Follow-ups (not in this PR)
--scsibuilds are also boot-safe: gateUserTargetPresentForIDon SBP-2 login and create/destroy the target from the login observer (framework hotplug model). Needs hardware verification with a scanner; will follow as a separate PR.-scsiasset.scsicontrollerfamily entitlement for real distribution signing, the default can be revisited.