# DF-5744 — apple_gmux: missing I/O-region length validation → out-of-bounds port I/O

## What

`sys/gnu/dev/misc/apple_gmux/apple-gmux.c` attach never validates the size of
the I/O resource it gets from the ACPI `_CRS`. `GMUX_MIN_IO_LEN` is defined at
apple-gmux.c:77 and **never referenced** — the upstream Linux v4.8 driver this
was ported from (`drivers/platform/x86/apple-gmux.c`) has

```c
if (gmux_data->iolen < GMUX_MIN_IO_LEN) { ... ret = -ENODEV; goto err_release; }
```

but the DragonFly port dropped it. On x86, `bus_read_1`/`bus_write_1` on an
IOPORT resource are raw `inb`/`outb` with **no bounds checking**, so with a
short `_CRS` the production driver performs reads/writes to I/O ports far
outside its rman allocation: version regs at offsets 0x04–0x06, and (when
those read 0xff) the indexed probe `gmux_is_indexed()` writes 0xaa/0x55/0x00
to offsets 0xcc–0xce and the indexed protocol touches 0xc2–0xc5, 0xd0, 0xd4.

Precondition: an ACPI gmux device (`APP000B`) whose `_CRS` window is smaller
than the registers the driver touches — i.e. crafted/malicious firmware, a
root-modified DSDT override, or a firmware bug. (Requires no Apple hardware:
the driver is a loadable KLD that will happily probe any `APP000B` device.)

## Rig

* `ssdt_a.aml` (generated by `make_ssdt.py`): one device `\_SB.ZZZ0`,
  `_HID "APP000B"`, `_CRS` = **4 ports at 0x333**.
* `gmuxobs.c` → `gmuxobs.ko`: canary module watching the 16550 **COM1 scratch
  register** at port 0x3ff — fully readable/writable, zero functional side
  effects. 0x333 + 0xcc = **0x3ff**, so `gmux_is_indexed()`'s first indexed
  probe write lands exactly on the canary.

## Build / run (guest, root)

```
cd /root/gmuxobs_a && make                          # gmuxobs.ko
# boot QEMU with: -acpitable file=ssdt_a.aml
kldload /root/gmuxobs_a/gmuxobs.ko                  # baseline: hw.gmuxobs_scr: 0
kldload apple_gmux                                  # PRODUCTION module
sysctl hw.gmuxobs_scr                               # expect 0xaa == 170
```

## Expected result (observed 2026-10-11, DragonFly 6.5-DEVELOPMENT X86_64_GENERIC)

```
apple_gmux0: <apple gmux controller> port 0x333-0x336 on acpi0   <- 4-port resource
apple_gmux: gmux device not present or IO disabled
device_probe_and_attach: apple_gmux0 attach returned -19
hw.gmuxobs_scr: 170                                               <- 0xaa canary hit
```

The production driver wrote 0xaa to port 0x3ff — **204 bytes past the end of
its 4-port allocation** — corrupting an unrelated device's register (here the
UART SCR; on real hardware whatever lives near the gmux window: PIC ELCR,
PM registers, SMBus, ...). Also 3 OOB reads at 0x337–0x339 (offsets 4–6 vs
size 4) before the indexed probe.

## Fix validation (same rig, patched module from fix.diff)

```
apple_gmux: gmux I/O region too small (4 bytes, need >= 120)
device_probe_and_attach: apple_gmux0 attach returned -19
hw.gmuxobs_scr: 0        <- canary untouched
```

## Files

* `make_ssdt.py` — SSDT generator (hand-encoded AML)
* `ssdt_a.aml` — the planted table
* `gmuxobs.c` / `Makefile` — canary observer KLD
* `run.log` — decisive run (full console capture)
* `dmesg.txt` — full dmesg of the rig boot
* `fix.diff` — 2 hunks: size validation (classic + indexed-probe minimum)
* `fix_validation.log` — patched-module run on the same rig
