# DF-4816 — iwm phy_db: unvalidated firmware chg_id (group index) → unbounded
group-array allocation + uint8_t truncation of group count in send path

## File
`sys/dev/netif/iwm/if_iwm_phy_db.c` (pass 2, GLM 5.3 re-audit)

## Class
CWE-197 (numeric truncation error) + CWE-770 (allocation without bounds /
uncontrolled total). Correctness / resource-exhaustion defect reachable only by
the device firmware (hostile-device model: compromised or buggy Wi-Fi firmware
image on Intel Wireless 7265/8000+ NICs). **Not** kernel memory corruption and
**not** reachable by an unprivileged local user through any syscall path.

## Build / run
There is **no runnable PoC** for this finding on the audit QEMU guest: the
defect requires an Intel Wireless 7265+/8000+ PCI device (8086:095a/095b/24f*/…)
whose firmware emits `IWM_CALIB_RES_NOTIF_PHY_DB` (0x6b) notifications with a
crafted first channel-group id. The guest has no such device (verified:
`pciconf -l` shows 7 generic QEMU devices, no 8086 wireless, no iwm module).
Verification is therefore static (code-path proof below); runtime reproduction
requires bare-metal hardware with a patched firmware image.

## What a hostile firmware sends (trigger description)
During the init-ucode calibration phase (driver flow: `iwm_run_init_ucode()` →
notif-wait callback `iwm_wait_phy_db_entry()` → `iwm_phy_db_set_section()`),
the firmware emits:

    struct iwm_calib_res_notif_phy_db {
        uint16_t type;      /* 4 = IWM_PHY_DB_CALIB_CHG_PAPD or 5 = CHG_TXP */
        uint16_t length;
        uint8_t  data[];    /* data[0..1] = chg_id (group index), fw-chosen */
    } __packed;

`chg_id` is taken verbatim from `data[0..1]` (if_iwm_phy_db.c:279 / :293) with
**no upper bound**, and two independent defects follow:

1. **Unbounded allocation / accumulation** (if_iwm_phy_db.c:285-290, 299-304):
   on the *first* CHG notification of each type the driver allocates
   `(chg_id + 1) * sizeof(struct iwm_phy_db_entry)` — up to 65536 entries =
   1 MiB per type — with `M_WAITOK|M_ZERO` **from the RX interrupt path**
   (`iwm_intr` → `iwm_notif_intr` → `iwm_handle_rxb` →
   `iwm_notification_wait_notify` → `iwm_wait_phy_db_entry`). Each subsequent
   CHG notification for a fresh index allocates `length` (up to 65535) more
   bytes of `M_DEVBUF` held until detach, bounded only by the calibration
   wait timeout — i.e. hundreds of MB of unreclaimable kernel memory from a
   few seconds of hostile notifications.

2. **uint8_t truncation** (if_iwm_phy_db.c:455-458 param
   `uint8_t max_ch_groups`; call sites 541-542 and 551-552 pass the `int`
   `n_group_papd`/`n_group_txp`):
   - `n_group_* >= 256` → count truncated mod 256 → groups ≥ 256 are
     silently never uploaded to the runtime firmware (radio runs with
     missing PAPD/TXP calibration — TX-power correctness hazard), or
     nothing at all is sent when the count is a multiple of 256.
   - `n_group_* == -1` (init value — fw sent **no** groups of that type)
     → passed as 255 → first `iwm_phy_db_get_section()` returns NULL →
     `iwm_phy_db_send_all_channel_groups()` returns EINVAL →
     `iwm_send_phy_db_data()` fails → `iwm_load_firmware()` aborts
     (if_iwm.c:4856-4857) → interface cannot start (device DoS).

## Expected result if run on real hardware with hostile fw
- dmesg: either `iwm_send_phy_db_data` failure / firmware load abort, or
  silent partial calibration upload; sustained `M_DEVBUF` growth in `vmstat -m`
  during the calibration window.

## Fix
See `fix.diff` (cap chg_id at 255; pass the group count as `int` and skip
non-positive counts).
