# DF-1221 — ena RX req_id used as array index without bounds (OOB read/write/panic)

## Verdict
**INCONCLUSIVE (not_testable on this guest)** — bug confirmed in source; the
Amazon ENA NIC is absent from the audit guest. Fix authored, applied, and the
`if_ena.ko` module compiled clean as a standalone module build.

## Finding summary
`ena_rx_mbuf()` in sys/dev/virtual/amazon/ena/ena.c uses
`req_id = ena_bufs[buf].req_id` (a uint16, range 0–65535, supplied by the
device/hypervisor) directly as an array index into `rx_ring->rx_buffer_info[]`
at :1459 and again at :1491 inside the multi-descriptor loop, **with no bounds
check**. `rx_buffer_info` is sized `ring_size` (max 1024) at :736/:744, so a
`req_id >= 1024` reads up to ~4 MB past the array into kernel heap. The
resulting `rx_info->mbuf` is a garbage pointer that is dereferenced and
written at :1465 (`mbuf->m_flags |= M_PKTHDR`) → kernel panic or arbitrary
kernel-memory write.

The driver **has** a validator — `validate_rx_req_id()` at :700 — and it is
called on the TX-completion path (`ena_com_tx_comp_req_id_get`,
`validate_tx_req_id`) and on the RX-refill path (:1012). But the RX-consume
path (`ena_rx_mbuf`) skips it entirely. The fix is therefore a one-line call
to the existing validator.

## Source confirmation (audited tree)
- ena.c:1446 — `uint16_t ntc, len, req_id, buf = 0;` — req_id is uint16.
- ena.c:1458 — `req_id = ena_bufs[buf].req_id;` — device-supplied, no validation here.
- ena.c:1459 — `rx_info = &rx_ring->rx_buffer_info[req_id];` — OOB index when req_id >= ring_size.
- ena.c:1464–1467 — `mbuf = rx_info->mbuf; mbuf->m_flags |= M_PKTHDR; mbuf->m_pkthdr.len = len; mbuf->m_len = len;` — deref + write through garbage mbuf.
- ena.c:1490–1491 — same pattern in the multi-descriptor loop.
- ena.c:699–717 — `validate_rx_req_id()` exists: logs, bumps `ierrors`, sets `reset_reason = ENA_REGS_RESET_INV_RX_REQ_ID`, returns EFAULT on out-of-range.
- ena.c:1012 — `rc = validate_rx_req_id(rx_ring, req_id);` — RX-refill path correctly calls it.
- ena.c:736 — `size = sizeof(struct ena_rx_buffer) * rx_ring->ring_size;`
- ena.c:744 — `rx_ring->rx_buffer_info = kmalloc(size, M_DEVBUF, M_WAITOK | M_ZERO);`

## Why not runtime-reproduced on this guest
The QEMU/KVM guest has no Amazon ENA NIC (only virtio-net). The `if_ena.ko`
module is present in `/boot/kernel/` but is not loaded (driver probe returns
ENXIO without matching hardware). The bug path is unreachable at runtime on
this guest.

Triggering the bug requires an Amazon ENA NIC (real or emulated) that emits an
RX completion with `req_id >= ring_size` — i.e. a malicious, buggy, or
compromised ENA device/hypervisor.

## Fix (fix.diff)
Call the existing `validate_rx_req_id()` before each `rx_buffer_info[req_id]`
indexing, returning `NULL` on out-of-range (the caller at :1646 already
handles `NULL` correctly — it releases the descriptors and aborts the packet):

```c
req_id = ena_bufs[buf].req_id;
if (unlikely(validate_rx_req_id(rx_ring, req_id)))
    return (NULL);
rx_info = &rx_ring->rx_buffer_info[req_id];
```
…and the same guard inside the multi-descriptor `while (--descs)` loop.

## Fix validation
- `git apply --check -p1` — clean.
- Applied to in-guest `/usr/src/sys/dev/virtual/amazon/ena/ena.c`; standalone
  module build (`make` in `/usr/src/sys/dev/virtual/amazon/ena`) — compiled
  clean, `if_ena.ko` produced, build rc=0.
- `fix_status: not_testable` — no ENA hardware on this guest.

## Run / reproduce
Not runnable on this guest. On an AWS EC2 Nitro instance (or any system with
an ENA device that can be made to emit a bad `req_id`), the bug would manifest
as a kernel panic at `mbuf->m_flags |= M_PKTHDR` or as a kernel-memory write
if the OOB read happens to land on a forged mbuf pointer.
