RX completion req_id used as array index without bounds check (OOB read/write/panic)
Summary
ena_rx_mbuf() at ena.c:1458-1459: req_id=ena_bufs[buf].req_id then rx_info=&rx_ring->rx_buffer_info[req_id] with NO bounds check. req_id is uint16 (0-65535), rx_buffer_info sized ring_size+1 (max 1025). TX path validates req_id in ena_com_tx_comp_req_id_get (:614) and validate_tx_req_id; RX refill path validates in validate_rx_req_id (:699/1012), but RX consume path does NOT. req_id>=1025 -> OOB read of ~4MB into kernel heap -> garbage mbuf pointer -> mbuf->m_flags write (:1465) -> kernel panic or memory corruption. Malicious/buggy ENA device/hypervisor. Fix: call validate_rx_req_id(rx_ring,req_id) before indexing rx_buffer_info.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1221 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | full narrative + path:line trace | 3.7 KB | β raw |
| README.md | readme | reproduce / preconditions | 1.0 KB | β raw |
| fix.diff | suggested-fix | call validate_rx_req_id before indexing rx_buffer_info | 1.2 KB | view raw |
| build.sh | build-log | standalone if_ena module build | 321 B | view raw |
| run.sh | run-log | no runtime trigger; static trace | 150 B | view raw |
| module_build.log | build-log | if_ena module build output (fix compiles) | 3.5 KB | view raw |
| env.txt | environment | guest uname, PCI devices, GENERIC config | 587 B | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1221 β ena RX req_id OOB index
Reproduce
Not runnable on the audit guest β no Amazon ENA NIC is attached. The
verification is a static source trace + a compiling fix.diff.
To validate the fix compiles as a standalone module:
cd /usr/src/sys/dev/virtual/amazon/ena
make obj
make
ls /usr/obj/usr/src/sys/dev/virtual/amazon/ena/if_ena.ko
Bug location
sys/dev/virtual/amazon/ena/ena.c:1458β1459 β req_id (device-supplied
uint16) is used as an index into rx_ring->rx_buffer_info[] (sized
ring_size β€ 1024) with no bounds check. The driver has validate_rx_req_id()
at :700 but does NOT call it on the RX-consume path (only TX-consume and
RX-refill). Out-of-range req_id reads up to ~4 MB OOB into kernel heap;
garbage mbuf pointer is dereffed+written at :1465.
Trigger preconditions (NOT met on this guest)
- An Amazon ENA NIC (AWS EC2 Nitro) that emits an RX completion with
req_id >= ring_sizeβ i.e. a malicious/buggy/compromised device.
Files
VERDICT.md,fix.diff,env.txt,module_build.log.
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, bumpsierrors, setsreset_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):
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 (makein/usr/src/sys/dev/virtual/amazon/ena) β compiled clean,if_ena.koproduced, 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.
Fix verification
not_testablecompile validated
kernel/module build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. ena RX req_id no validate_rx_req_id -> OOB rx_buffer_info -> garbage mbuf ptr. ena module, no ENA NIC.
No comments yet.