ena_com_admin_destroy() dereferences comp_ctx four lines before its NULL check β OOM-gated NULL-deref panic in the ena(4) attach path
Summary
ENA_WAIT_EVENT_DESTROY(admin_queue->comp_ctx->wait_event) dereferences comp_ctx before the NULL guard. When the M_NOWAIT kmalloc in init_comp_ctxt fails, the admin_init error unwind calls the destroy with comp_ctx==NULL -> kernel panic at device attach. Secondary: only comp_ctx[0] of 32 wait events is destroyed. Memory-pressure-gated local DoS. Move-under-the-guard fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3937 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.9 KB | β raw | |
| VERDICT.md | β | 2.5 KB | β raw | |
| fix.diff | β | 634 B | view raw | |
| env.txt | β | 984 B | view raw | |
| manifest.json | β | 886 B | view raw | |
| verdict.json | β | 2.5 KB | view raw |
DF-3937 β ena_com_admin_destroy() dereferences comp_ctx BEFORE its NULL check (OOM-gated NULL deref at attach)
Finding
sys/dev/virtual/amazon/ena/ena-com/ena_com.c:1581:
void ena_com_admin_destroy(struct ena_com_dev *ena_dev)
{
...
ENA_WAIT_EVENT_DESTROY(admin_queue->comp_ctx->wait_event); /* :1581 β deref */
ENA_SPINLOCK_DESTROY(admin_queue->q_lock);
if (admin_queue->comp_ctx) /* :1585 β NULL check */
ENA_MEM_FREE(ena_dev->dmadev, admin_queue->comp_ctx);
ENA_WAIT_EVENT_DESTROY(w) expands (DragonFly port, ena_plat.h:231-234) to
cv_destroy(&((w).wq)); lockuninit(&((w).lock)); β i.e. it dereferences the
pointer. If ena_com_admin_init() failed in ena_com_init_comp_ctxt()
(ena_com.c:1713-1715 β ena_com.c:302-306: comp_ctx = ENA_MEM_ALLOC(...)
returned NULL β return ENA_COM_NO_MEM), the error path
ena_com.c:1761-1762 calls ena_com_admin_destroy(ena_dev) with
admin_queue->comp_ctx == NULL β NULL dereference panic during device
attach. Additionally, even on the success path only comp_ctx[0]'s wait
event is destroyed although all q_depth (32) entries were initialized in
ena_com_init_comp_ctxt (ena_com.c:308-312) β benign on DragonFly
(cv_destroy/lockuninit are statistical no-ops) but sloppy lifetime handling.
Trigger
ENA device attach under kmalloc failure for the 32-entry comp_ctx array
(M_DEVBUF, M_NOWAIT). The DF-3799-analogue pattern (inverted/absent NULL
guard) but reachable on an allocation failure, not dead code.
Severity rationale
Low: requires local memory pressure at attach time on a machine with an ENA NIC; impact is a kernel NULL-deref panic (DoS), no corruption (write is via NULL+offset within the cv/lock structs at address ~0 β fault).
Why inconclusive on this guest
No ENA PCI function on the audit guest (env.txt); the destroy path only runs from ena(4) attach/detach.
DF-3937 β VERDICT
Status: inconclusive (hardware-gated) β source-level certainty: certain. Impact class: NULL-pointer dereference panic (CWE-476), OOM-gated, at device attach.
Trace
sys/dev/virtual/amazon/ena/ena-com/ena_com.c:1713βret = ena_com_init_comp_ctxt(admin_queue);insideena_com_admin_init().ena_com.c:302-306βqueue->comp_ctx = ENA_MEM_ALLOC(queue->q_dmadev, size);(kmalloc(..., M_DEVBUF, M_NOWAIT|M_ZERO),ena_plat.h:297) β on failure returnsENA_COM_NO_MEMwithcomp_ctx == NULL.ena_com.c:1714-1715βgoto error;βena_com.c:1761-1762βerror: ena_com_admin_destroy(ena_dev);ena_com.c:1581βENA_WAIT_EVENT_DESTROY(admin_queue->comp_ctx->wait_event);βena_plat.h:231-234(cv_destroy(&w.wq); lockuninit(&w.lock);) β NULL deref panic β and this is four lines BEFORE theif (admin_queue->comp_ctx)guard at:1585.- Callers reaching
ena_com_admin_init:ena.c:3220(ena_attach β ena_device_init). So the panic happens in the PCI attach path whenever the 32-entry comp_ctx allocation fails β a machine-local memory-pressure window, not attacker-timed in general (an unprivileged local user can sprayM_DEVBUFto make NOWAIT allocations fail during a driver_reload/devclass event, which is the realistic DoS shape).
Secondary (same function, non-crashing): only comp_ctx[0]'s wait event is
destroyed although all 32 were ENA_WAIT_EVENT_INIT'd (:308-312); the
other 31 cv/lock pairs are abandoned β on DragonFly cv_destroy/lockuninit
are accounting-only, so no resource leak of substance.
Why not reproduced
Requires an ENA PCI function to reach ena attach; the audit guest has none
(env.txt, vendor 0x1d0f absent). inconclusive per batch convention.
Precedent: DF-3799 (ena.c) documented the same pattern (inverted NULL
check) as Info because it was dead code; here the guard order is wrong on a
reachable error path, so the finding is filed Low with certainty certain at
source level.
Fix
fix.diff moves the ENA_WAIT_EVENT_DESTROY under the existing NULL check.
fix_status
not_testable β no ENA hardware on the guest.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testableFix not validated on the guest (no ENA hardware, env.txt). fix.diff moves ENA_WAIT_EVENT_DESTROY under the existing NULL guard at ena_com.c:1585 β a pure ordering fix authored post-verification.
findings/poc/DF-3937/fix.diff + VERDICT.md
Confirmed kernel references
Detail
Exploit chain
local memory pressure + ena attach/reload -> ena_com_init_comp_ctxt alloc fails -> ena_com_admin_init error path -> ena_com_admin_destroy -> cv_destroy(&NULL->wq) -> kernel panic (DoS)
Evidence (decisive lines)
findings/poc/DF-3937/VERDICT.md (5-step trace) + fix.diff + env.txt
PoC changes
No seed PoC; hardware-gated.
Verified recommended fix
Move ENA_WAIT_EVENT_DESTROY inside the comp_ctx NULL guard (fix.diff).
Verdict
ena_com_admin_destroy dereferences admin_queue->comp_ctx at ena_com.c:1581 (ENA_WAIT_EVENT_DESTROY -> cv_destroy/lockuninit per ena_plat.h:231-234) FOUR LINES BEFORE the NULL check at :1585. Reached from ena_com_admin_init's error unwind (:1761-1762) when ena_com_init_comp_ctxt's kmalloc (M_NOWAIT) fails (:302-306) β i.e. NULL-deref panic in the ena(4) PCI attach path under memory pressure (an unprivileged user can pressure M_DEVBUF around a driver reload to shape this). Secondary: only comp_ctx[0] of the 32 initialized wait events is destroyed. Low severity / certain at source; hardware-gated (no ENA device on guest) => inconclusive runtime classification. Pattern precedent: DF-3799 (dead-code variant, Info).
No comments yet.