apple_smc_sms_intr() unconditionally reads the ISA int-port via ASMC_INTPORT_READ while MMIO-backend devices have sc->sc_ioport == NULL β NULL resource deref β panic in interrupt context
Summary
The SMS interrupt handler executes bus_read_1(sc->sc_ioport, 0x1f) with no backend check, but MMIO Macs never allocate the port resource - rman_get_bustag is a raw deref, page-0 read in ISR context = panic. The handler is installed whenever SMS keys are detected (they can be over MMIO - exactly the HDD-era motion-sensor population). Physical unauthenticated trigger (machine motion). Guard-the-backend fix (git-apply-verified).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4730 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.3 KB | β raw | |
| VERDICT.md | β | 4.9 KB | β raw | |
| verify.sh | β | 1.2 KB | view raw | |
| static_proof.log | β | 2.0 KB | view raw | |
| env.txt | β | 609 B | view raw | |
| fix.diff | β | 574 B | view raw | |
| verdict.json | β | 2.9 KB | view raw |
DF-4730 β apple_smc: apple_smc_sms_intr() reads the ISA port backend on MMIO devices β NULL resource deref β panic in interrupt context
File: sys/dev/apple/smc/smc_io.c β pass 2 (GLM 5.3 re-audit)
Severity: Low Β· CWE-476 Β· confidence: likely (logic certain; hardware population unverified)
What
The SMS interrupt handler is backend-blind:
void
apple_smc_sms_intr(void *arg) /* smc_io.c:610 */
{
...
if (!sc->sc_sms_intr_works)
return;
SMC_LOCK(sc);
type = ASMC_INTPORT_READ(sc); /* smc_io.c:620 */
...
ASMC_INTPORT_READ(sc) is bus_read_1(sc->sc_ioport, 0x1f) (smc.h:113).
But on MMIO-backend machines the driver never allocates sc->sc_ioport:
- smc.c:163-176 β MMIO window tried first; on success
sc->sc_is_mmio = 1. - smc.c:178-186 β the IOPORT resource is allocated only
if (!sc->sc_is_mmio).
bus_read_1(r, o) expands to
bus_space_read_1(rman_get_bustag(r), rman_get_bushandle(r), o) and
rman_get_bustag(r) is the plain macro ((r)->r_bustag) (sys/sys/rman.h:151)
β with r == NULL this is a NULL+offset read β page-0 fault in interrupt
context β kernel panic.
Reachability
- Requires an Apple machine whose SMC exposes the MMIO window and the SMS
key set (
MO__,MOCN, ... β detect_capabilities, smc.c:633-643, works over either backend) and declares the SMC IRQ. The driver's own header comment (smc.h:68-71) documents that "MMIO can exist without T2 (e.g. iMac14,1 has MMIO but no T2)" β iMac14,x (2013) is HDD-era hardware, i.e. exactly the population that carries a Sudden Motion Sensor. On such a machine any SMC event interrupt (free-fall / shock / light-sensor) takes the NULL path. - The IRQ handler is registered whenever
sc_has_smsis set (smc.c:478), with no backend check anywhere on the path. - Trigger is physical (machine motion / HDD-park event), not attacker-typed; no privilege involved.
Reproduce (static proof β runnable)
Run ./verify.sh in this directory. It greps the exact chain:
smc_io.c:620 β smc.h:113 β bus_read_1/rman_get_bustag (rman.h:151), and
smc.c:163-186 showing sc->sc_ioport is NULL whenever sc_is_mmio.
Why not verified on the QEMU guest
The audit guest has no Apple SMC (no ACPI APP0001 device, no apple_smc
sysctls β see env.txt). Injecting an APP0001 ACPI device with a fake MMIO
window cannot emulate SMC protocol behaviour (the status-ready bit needs to
self-assert), so the driver falls back / detaches before the interrupt path
can be reached. Status recorded as untested (permitted enum); impact on
target hardware would be panic.
Recommended fix
Dispatch (or at least guard) the interrupt-port read by backend; there is no documented MMIO equivalent of the 0x1f int-port on the T2 MMIO interface, so the safe minimal fix is to skip the hardware read when the port backend is absent:
--- a/sys/dev/apple/smc/smc_io.c
+++ b/sys/dev/apple/smc/smc_io.c
@@ -617,11 +617,17 @@ apple_smc_sms_intr(void *arg)
if (!sc->sc_sms_intr_works)
return;
+ /*
+ * The int-status port exists only on the ISA-port backend; on the
+ * MMIO backend sc_ioport is NULL by construction (smc.c:178-186).
+ */
+ if (sc->sc_ioport == NULL)
+ return;
+
SMC_LOCK(sc);
type = ASMC_INTPORT_READ(sc);
sc->sc_sms_intrtype = type;
SMC_UNLOCK(sc);
VERDICT β DF-4730
- status: untested (permitted enum; contract category would be "skipped/not_testable")
- reproduced: 0 Β· impact: none (demonstrated) β would be
panicon target hardware - confidence: likely (code logic certain; existence of MMIO+SMS Apple hardware probable but unverified on a live unit)
Narrative
Pass-2 audit of sys/dev/apple/smc/smc_io.c (pass-1 already filed the
fanid/MMIO-underfill stack-leak family against the sibling files β DF-1860,
DF-2129, DF-2402, DF-2403 β not re-reported here).
New finding: the SMS interrupt handler is backend-blind.
apple_smc_sms_intr() (smc_io.c:609-630) unconditionally executes
ASMC_INTPORT_READ(sc) at smc_io.c:620, which is
bus_read_1(sc->sc_ioport, 0x1f) (smc.h:113). On MMIO-backend machines the
driver never allocates sc->sc_ioport:
- smc.c:163-176 β MMIO window probed first (
apple_smc_try_enable_mmio); on successsc->sc_is_mmio = 1. - smc.c:178-186 β
bus_alloc_resource_any(SYS_RES_IOPORT)runs onlyif (!sc->sc_is_mmio);sc->sc_ioportstays NULL.
bus_read_1(r,o) = bus_space_read_1(rman_get_bustag(r),
rman_get_bushandle(r), o); rman_get_bustag(r) is the raw macro
((r)->r_bustag) (sys/sys/rman.h:151). With r == NULL this is a page-0
read in interrupt context β kernel panic.
The handler is registered whenever sc_has_sms (smc.c:434-483), and SMS
detection (apple_smc_key_getinfo, smc_io.c:142-183) dispatches to the MMIO
backend when sc_is_mmio β so an MMIO Mac that has the MO__/MOCN/β¦ key
set gets the IRQ installed and the NULL path armed. The driver's own header
(smc.h:68-71) states MMIO exists without T2 "e.g. iMac14,1" β HDD-era
Macs, i.e. the Sudden-Motion-Sensor population. Trigger: any SMC event
interrupt (free-fall, shock, light-sensor) β physical, no privilege needed,
but hardware-specific.
Why untested (not false_positive)
Code path is statically certain (run ./verify.sh, output in
static_proof.log). Not a false positive: no backend guard exists anywhere
between IRQ delivery and the port read. Not runtime-verified because the
audit guest has no Apple SMC (no ACPI APP0001, no apple_smc sysctls β
env.txt). Faking one via an injected SSDT cannot emulate SMC MMIO protocol
behaviour (status-ready self-assertion), so apple_smc_try_enable_mmio
rejects before the interrupt path arms. Filed Low: specific hardware +
physical trigger, panic-only.
Exploit chain
None β panic in ISR context; no memory disclosure, no control-flow influence over the faulting value (fixed NULL+offset).
Negative results (classes hunted and killed in smc_io.c)
- fanid stack-leak via
apple_smc_fan_getstringreturning non-terminatedbuf+4+ DF's unboundedstrleninsysctl_handle_string(kern_sysctl.c:1171): already filed as DF-1860/DF-2403 (smc_sysctl.c) and DF-2129/DF-2402 (smc_mmio.c) β not re-reported. - Port-path
apple_smc_key_read/_write/_getinfo/_dump_by_index: all writes bounded by fixed ASMC_KEYLEN/ASMC_TYPELEN/ASMC_KEYINFO_RESPLEN constants into caller buffers of exactly those sizes (smc.c:687-688, smc_io.c:335-336, 256-257); retry loops bounded (10 / ASMC_MAXRETRIES) β clean. - MMIO branch of
apple_smc_key_dump_by_index(smc_io.c:196-202):getbyindexNUL-terminateskey[ASMC_KEYLEN](smc_mmio.c:185) β clean. apple_smc_scan_sensor_range/detect_sensorsarray fills: bounded bymaxcount/ ASMC_TEMP_MAX / ASMC_MAX_SENSORS before every store (smc_io.c:348-349, smc.c:731/738/784) β clean.apple_smc_fan_getvalue/_setvaluefankey[5]viaksnprintf("F%d.."): fan index β€ ASMC_MAXFANS-1 = 5 (clamped, smc.c:608-611), single digit β fits β clean.apple_smc_float_to_u32/_u32_to_floatshift arithmetic: exp bounded [0,30] / bc bounded [0,30] β no UB β clean.- Locking: mmio dispatch happens before SMC_LOCK in every wrapper (smc_io.c:73-76, 110-113, 148-151, 196-204), mmio helpers take the lock themselves β no recursive acquire of the non-spin lockmgr lock β clean.
sc_nkeysnegative frombe32dec(smc.c:613-614) β binary search over ~2^31 indices: bounded at ~31 hardware round-trips at attach, self-controller data only β not attacker-influenced β noted, not filed.- SMS task/ISR lifetime vs detach:
bus_teardown_intrprecedestaskqueue_drain/taskqueue_free(smc.c:520-533) β clean.
Fix validation
Not possible on this guest (no Apple SMC): fix_status: not_testable.
fix.diff guards sc->sc_ioport == NULL at handler entry (MMIO devices
have no int-port; returning early is the T2-correct behaviour since T2
Macs have no SMS anyway).
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablefix.diff authored (early-return NULL guard in apple_smc_sms_intr) but not build-validated: no Apple SMC hardware on the audit guest.
findings/poc/DF-4730/fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
findings/poc/DF-4730/static_proof.log (steps 1-6: handler reads INTPORT unconditionally, macro definition, sc_ioport NULL when MMIO, IRQ registered backend-blind, detection works over either backend, rman_get_bustag raw deref); VERDICT.md (full narrative + killed candidates incl. the already-filed fanid leak family DF-1860/2129/2402/2403); verify.sh (runnable)
PoC changes
No PoC seed existed; authored a runnable static proof script (verify.sh) instead of a hardware PoC since the finding is hardware-gated.
Verified recommended fix
Return early from apple_smc_sms_intr() when sc->sc_ioport is NULL (MMIO backend has no int-port; T2 machines have no SMS).
Verdict
Pass-2 finding: apple_smc_sms_intr() (smc_io.c:620) unconditionally executes ASMC_INTPORT_READ(sc) = bus_read_1(sc->sc_ioport, 0x1f) (smc.h:113), but on MMIO-backend Macs sc->sc_ioport is NULL by construction (smc.c:178-186 allocates the IOPORT resource only when !sc_is_mmio). rman_get_bustag(NULL) is a raw ((r)->r_bustag) deref (sys/sys/rman.h:151) -> page-0 fault in interrupt context -> kernel panic. Armed on any MMIO SMC machine that also exposes the SMS key set (driver's own header documents MMIO-without-T2 hardware, e.g. iMac14,1, which is HDD-era = SMS population); trigger is an SMC event interrupt. Runtime verification impossible on the audit guest (no Apple SMC hardware; a faked ACPI APP0001 device cannot emulate SMC MMIO protocol). Static chain machine-checked by verify.sh/static_proof.log. Severity Low: specific hardware, physical trigger, panic-only.
No comments yet.