# DF-3578 — Divide-by-zero kernel panic in iwn4965_set_txpower() via malicious EEPROM

## What this is

Evidence pack for a division by zero in `sys/dev/netif/iwn/if_iwn.c:5707-5715`
(`iwn4965_set_txpower()`), reachable with attacker-controlled EEPROM contents
(malicious/corrupt card — the pass-2 strategy's "EEPROM parse" surface).

## Root cause

`iwn4965_read_eeprom()` bulk-loads the power-group sample table straight from
EEPROM with **no validation** (if_iwn.c:2314):

```c
iwn_read_prom_data(sc, IWN4965_EEPROM_BANDS, sc->bands, sizeof sc->bands);
```

`iwn4965_set_txpower()` then interpolates between the two per-band channel
samples (if_iwn.c:5707-5715):

```c
power = interpolate(chan, chans[0].num, chans[0].samples[c][1].power,
                           chans[1].num, chans[1].samples[c][1].power, 1);
```

with (if_iwn.c:5632-5637):

```c
#define fdivround(a, b, n)   ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n))
#define interpolate(x, x1, y1, x2, y2, n) \
        ((y1) + fdivround(((int)(x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n))
```

The divisor is `(x2) - (x1)` = `chans[1].num - chans[0].num`, both raw EEPROM
bytes. If a malicious EEPROM stores the **same channel number in both sample
slots**, the divisor is 0 → integer divide error → kernel panic on
`ifconfig wlan0 up` (iwn_config → ops->set_txpower, if_iwn.c:6798) and again
from iwn_auth (if_iwn.c:7199) / 4965 temperature recalibration.

Contrast: the neighboring EEPROM values *are* range-checked
(`maxpwr5GHz/maxpwr2GHz`, if_iwn.c:2305-2309) — the band sample channels are
not.

## What this pack proves

`iwn_eeprom_div0.c` runs the verbatim macros with EEPROM-fed values routed
through `volatile` storage (so the compiler cannot constant-fold the
division — the first, non-volatile harness version was folded by gcc -O2 and
did not fault; see VERDICT.md):

- control (chans[].num = 36/64): interpolates fine, prints `power=40 OK`.
- malicious (chans[].num = 36/36): **SIGFPE, exit 136**, deterministic 4/4.

In the kernel the same `idiv` raises #DE → panic. Full in-kernel repro needs
a 4965 card with a re-flashed EEPROM, which the audit guest (virtio-only,
no Intel WiFi device) cannot provide.

## Build / run (on the DragonFly guest)

```
cc -O2 -Wall -o iwn_eeprom_div0 iwn_eeprom_div0.c
./iwn_eeprom_div0       # expect: control OK, then SIGFPE (exit 136)
```

## Fix

`fix.diff` — guard the interpolation divisor (skip/clamp when
`chans[1].num <= chans[0].num`), and/or validate the band table after
`iwn_read_prom_data`.
