# VERDICT — DF-4730

* **status: untested** (permitted enum; contract category would be "skipped/not_testable")
* **reproduced: 0** · **impact: none (demonstrated)** — *would be `panic` on 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 success `sc->sc_is_mmio = 1`.
* smc.c:178-186 — `bus_alloc_resource_any(SYS_RES_IOPORT)` runs **only**
  `if (!sc->sc_is_mmio)`; `sc->sc_ioport` stays 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_getstring` returning non-terminated
  `buf+4` + DF's unbounded `strlen` in `sysctl_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):
  `getbyindex` NUL-terminates `key[ASMC_KEYLEN]` (smc_mmio.c:185) — clean.
* `apple_smc_scan_sensor_range` / `detect_sensors` array fills: bounded by
  `maxcount` / ASMC_TEMP_MAX / ASMC_MAX_SENSORS before every store
  (smc_io.c:348-349, smc.c:731/738/784) — clean.
* `apple_smc_fan_getvalue/_setvalue` `fankey[5]` via `ksnprintf("F%d..")`:
  fan index ≤ ASMC_MAXFANS-1 = 5 (clamped, smc.c:608-611), single digit —
  fits — clean.
* `apple_smc_float_to_u32/_u32_to_float` shift 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_nkeys` negative from `be32dec` (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_intr` precedes
  `taskqueue_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.
