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

netmap_mem_rings_create cleanup path leaks every allocated packet buffer: repeated failing ring creation permanently drains the global buffer pool (latent β€” module does not build on DFly)

Summary

On mid-way allocation failure, netmap_mem_rings_create jumps to cleanup which calls netmap_free_rings(na) - that helper only releases ring objects to the ring pool; it never releases the packet buffers whose indices sit in the successfully-allocated rings' slots. The correct teardown, netmap_mem_rings_delete, walks every slot and calls netmap_free_buf before freeing the rings. Each failed creation permanently leaks num_rings*slots buffers (bitmap bits stay 'in use', objfree never restored); repeated failing binds drain NETMAP_BUF_POOL to objfree==0 and every subsequent bind returns ENOMEM until reboot. LATENT (platform fact re-verified in-guest: module does not build - if_unused7 mismatch, build log in pack). Once netmap compiles: unpriv /dev/netmap user triggers allocation-failure loops -> global netmap memory-poisoned state. Fix: release slot buffers in the cleanup path mirroring rings_delete.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3396 Β· 5 files
FileTypeDescriptionSize
VERDICT.md β€” 2.2 KB ↓ raw
netmap_build.log β€” 12.2 KB view raw
fix.diff β€” 785 B view raw
manifest.json β€” 657 B view raw
verdict.json β€” 2.0 KB view raw
VERDICT.md
↓ download raw

VERDICT β€” DF-3396: analysis-only (module does not build on DragonFly)

Root cause

netmap_mem_rings_create() (sys/net/netmap/netmap_mem2.c:918-993): on allocation failure mid-way (either netmap_ring_malloc or netmap_new_bufs failing for any ring) it jumps to cleanup: which calls netmap_free_rings(na) (netmap_mem2.c:892-910). That helper only releases the ring objects back to the ring pool (netmap_ring_free per ring); it never releases the packet buffers whose indices sit in the successfully-allocated rings' slots (ring->slot[i].buf_idx, allocated by netmap_new_bufs at :948/:977).

Contrast the correct teardown, netmap_mem_rings_delete() (netmap_mem2.c:995-1016), which walks every slot and calls netmap_free_buf(na->nm_mem, ring->slot[i].buf_idx) before freeing the rings.

Consequence (latent)

Each failed netmap_mem_rings_create permanently leaks nkr_num_slots * num_rings buffers from the (global) NETMAP_BUF_POOL: their bitmap bits stay clear ("in use") and objfree is never restored. Repeated failing binds (e.g. rings too large for the current pool configuration, or ring pool exhaustion after a sysctl resize) drain the buffer pool until objfree hits 0 -> every subsequent netmap bind fails with ENOMEM until reboot/module reload. Memory-pressure DoS by an unprivileged user with access to /dev/netmap, requiring only the ability to trigger allocation failure repeatedly.

Why no PoC

The netmap module does not build on this tree β€” verified concretely: cd /usr/src/sys/net/netmap && make fails with netmap_kern.h:747:27: error: 'struct ifnet' has no member named 'if_unused7' (15 errors, -Werror, EXIT=1) β€” see netmap_build.log. The finding is therefore latent: it becomes reachable the moment the module is fixed/ported. Consistent with pass-1 DF-0546..DF-0550, which were filed at analysis confidence for the same reason.

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_testable
baseline no→ patch + rebuild →patched clean

fix.diff authored; cannot be built/validated because the netmap module itself does not compile on this tree.

fix.diff
↓ fix.diffper-fix-DF-3396

Confirmed kernel references

Detail

Evidence (decisive lines)

['VERDICT.md β€” cleanup-vs-delete asymmetry at netmap_mem2.c:987 vs :1005-1011', 'netmap_build.log β€” module build failure on this tree (15 errors)']

PoC changes

No executable PoC possible; analysis-only finding with concrete build-failure evidence.

Verified recommended fix

In the cleanup path, free each allocated ring's slot buffers (netmap_free_buf) before netmap_free_rings, mirroring netmap_mem_rings_delete.

Verdict

Latent (analysis-verified): netmap_mem_rings_create's cleanup path (netmap_mem2.c:987) frees ring objects but leaks every already-allocated packet buffer referenced by those rings' slots, unlike netmap_mem_rings_delete (:1005-1011) which frees slot buffers first; repeated failing ring creations drain the global buffer pool to permanent ENOMEM. PoC impossible on this tree: the netmap module itself does not compile (ifnet 'if_unused7' mismatch, netmap_build.log, EXIT=1).