β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1221

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1221 Β· 9 files
FileTypeDescriptionSize
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
README.md readme reproduce / preconditions
↓ download 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.
VERDICT.md verdict full narrative + path:line trace
↓ download raw

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):

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.

Fix verification

not_testable

compile 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.