# DF-3719 — mxge firmware image load: PIO copy unbounded vs the SRAM mapping; short-inflate copies uninitialized heap to the device

## Vulnerability (firmware-file trust family, DF-3573/DF-3631)

`sys/dev/netif/mxge/if_mxge.c` `mxge_load_firmware_helper()` (:651-729):

1. **Unbounded SRAM write.** The claimed uncompressed size is taken from
   the firmware *registration metadata* — `fw_len = (size_t)fw->version`
   (:685), the third field of `FIRMWS = <file>:<name>:<uncompressed-size>`
   in sys/dev/netif/mxge/fw/*/Makefile (e.g. mxge_eth_z8e:377284).  A
   buffer of `fw_len` bytes is kmalloc'd (:686) and, after a header check
   (:699-705), the whole `fw_len` region is copied to the NIC via
   `mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i, ...)` (:713-719).
   **Nothing relates `fw_len` to the SRAM window**: `mxge_load_firmware`
   passes `size = sc->sram_size` as `*limit` (:910-911) precisely so the
   helper could check — but the helper simply overwrites it with `*limit =
   fw_len` (:721) without ever comparing.  A crafted/mismatched firmware
   module with claimed size > `sram_size - MXGE_FW_OFFSET` (~917 KB of
   usable space behind offset 1 MB in the ~1.87 MB mapping, :4290) PIO-
   writes past the end of the `pmap_mapdev` BAR mapping → kernel VA
   corruption.
2. **Uninitialized heap to the device.** `inflate()` may return
   `Z_STREAM_END` with `zs.total_out < fw_len` (compressed stream shorter
   than the registered size).  The copy loop (:713) still copies `fw_len`
   bytes from the kmalloc'd (uninitialized) buffer — up to
   `fw_len - total_out` bytes of kernel heap contents are written into NIC
   SRAM.
3. (Edge) a fw module registered with `version == NULL` yields
   `fw_len == 0`: `kmalloc(0)` then `*(uint32_t *)(inflate_buffer +
   MCP_HEADER_PTR_OFFSET)` (:700) reads 4 bytes at +0x3c out of a
   zero-sized allocation before any check runs.

The zlib stream itself is validated (`!= Z_STREAM_END` → EIO, :692-696)
and the header offset is bounds-checked (`hdr_offset & 3` or
`hdr_offset + sizeof(*hdr) > fw_len`, :701) — so the *parse* is sound; the
missing piece is the size relationship to `*limit` and the true inflated
length.

## Threat model

Firmware images are kernel modules built from sys/contrib/dev/mxge/*.fw.uu
(DF-3573/DF-3631 family): loading one requires root (`kldload`), so this is
a root-supplied-input hardening gap (Low), not an unprivileged attack —
but it is also the guard against a *corrupted* shipped image (build-box
compromise, truncated file where metadata and payload disagree).

## Verification

Hardware-gated: `mxge_load_firmware_helper` runs at attach (:4341 via
mxge_select_firmware) — the guest has no Myricom device.  Source-certain;
`inconclusive` per family convention.

## Fix

`fix.diff`: clamp `fw_len` to `zs.total_out` after a successful inflate,
and reject images that don't fit `*limit - MXGE_FW_OFFSET` before the copy
loop (git-apply clean).
