# DF-0999 — rum_set_sleep_time divide-by-zero (zero beacon interval)

## Verdict
**NOT TESTABLE on default guest** (requires Ralink RT2573 USB WiFi adapter
associating with a malicious AP, neither present). Bug is real and
confirmed by source review; `net80211` *does* flag `bintval=0` as
invalid but the flag is never enforced, so the bad value reaches the
divide. The fix.diff compiles cleanly as a KLD module (see
`module_build.log`).

## Mechanism (cited)

`rum_set_sleep_time()` at `sys/bus/u4b/wlan/if_rum.c:2662-2691`:

```c
2671:   exp = ic->ic_lintval / bintval;     /* <-- #DE if bintval == 0 */
2672:   delay = ic->ic_lintval % bintval;
```

`bintval` is passed in from `rum_enable_tsf_sync()` at
`sys/bus/u4b/wlan/if_rum.c:2184`:

```c
2184:   bintval = vap->iv_bss->ni_intval;
...
2220:   return (rum_set_sleep_time(sc, bintval));
```

`ni_intval` is copied verbatim from the beacon IE at
`sys/netproto/802_11/wlan/ieee80211_input.c:545`:
`scan->bintval = le16toh(*(uint16_t *)frm);` and reaches
`ni->ni_intval = sp->bintval;` at
`sys/netproto/802_11/wlan/ieee80211_node.c:1525` without modification.

### Important refinement of the original claim
The finding summary states net80211 "copies verbatim ... with NO non-zero
validation." That is **inaccurate but inconsequential**: net80211 *does*
check at `sys/netproto/802_11/wlan/ieee80211_input.c:700-708`:

```c
700:   if (!(IEEE80211_BINTVAL_MIN <= scan->bintval &&
701:         scan->bintval <= IEEE80211_BINTVAL_MAX)) {
702:       IEEE80211_DISCARD(vap, ...);
706:       vap->iv_stats.is_rx_badbintval++;
707:       scan->status |= IEEE80211_BPARSE_BINTVAL_INVALID;
708:   }
```

(IEEE80211_BINTVAL_MIN=25, MAX=1000 per `sys/netproto/802_11/ieee80211.h:1337-1338`).

**But** `IEEE80211_BPARSE_BINTVAL_INVALID` (0x40, defined at
`sys/netproto/802_11/ieee80211_scan.h:212`) is **never checked anywhere**.
The only BPARSE_* flag the scan path consumes is `OFFCHAN`
(`sys/netproto/802_11/wlan/ieee80211_scan_sta.c:296,319` and
`sys/netproto/802_11/wlan/ieee80211_hostap.c:1707,1768`). So the bad
bintval flows through `ise->se_intval = sp->bintval;`
(`ieee80211_scan_sta.c:308`) → `ni->ni_intval = sp->bintval;`
(`ieee80211_node.c:1525`) → `rum_set_sleep_time(0)` → **#DE / kernel panic**.

`ic->ic_lintval` defaults to 100 (non-zero), so the divide fires on a zero
`bintval` argument regardless of `ic_lintval`.

## Impact
- **Kernel panic / DoS** (#DE on divide-by-zero).
- Triggerable remotely within radio range by a malicious AP broadcasting
  `beacon_int = 0` once the victim STA attempts to associate.
- `CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H` (Medium as filed).

## Why not tested on the guest
- No Ralink RT2573 USB WiFi adapter is attached to the QEMU guest.
- `if_rum.ko` is not loaded.
- Reproduction requires a USB WiFi adapter in STA mode within range of a
  malicious AP — outside the audit guest's capabilities.

## Fix
`fix.diff` — at the top of `rum_set_sleep_time()`, treat `bintval == 0`
as `1` to avoid the trap. This is the most localized defense; a more
thorough fix would be to enforce `IEEE80211_BPARSE_BINTVAL_INVALID` in
net80211 (drop the beacon / refuse association when the flag is set), but
that is a larger change in another subsystem.

## Compilation check
Fix (applied with DF-0997 and DF-0998) compiles cleanly into `if_rum.ko`.
See `module_build.log`.

## Files
- `fix.diff` — guard `bintval == 0` in `rum_set_sleep_time`
- `module_build.log` — proof the patched `if_rum.c` compiles
- `VERDICT.md`, `README.md`, `manifest.json`
