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

mn_attach error-path asymmetry: discarded BAR resource handles (unreleasable), leaking ENXIO returns, failures reported as attach success, dangling sc->node after node destruction, and no device_detach

Summary

Both memory-BAR handles live only in a local variable (only the virtual/physical values are stored) so they can never be released; each early ENXIO leaks everything allocated before it. Failures are returned as SUCCESS (bus-master-test failure, ng_make_node failure). The ng_name_node failure path destroys the node while sc->node keeps the dangling pointer in the still-live softc with interrupts registered - and still returns success. No device_detach exists at all. Deterministic source demonstration (0 release/0 detach occurrences). Bookkeeping + fail-correctly + NULL-the-pointer fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4343 Β· 8 files
FileTypeDescriptionSize
README.md β€” 3.8 KB ↓ raw
VERDICT.md β€” 2.3 KB ↓ raw
run.sh β€” 181 B view raw
run.log β€” 258 B view raw
env_guest.txt β€” 569 B view raw
fix.diff β€” 2.9 KB view raw
verdict.json β€” 2.8 KB view raw
manifest.json β€” 678 B view raw

DF-4343 β€” mn_attach error-path asymmetry: unreleasable/leaked BARs, success-returned failures, dangling sc->node, no detach

  • File: sys/dev/netif/mn/if_mn.c
  • Lines: 1301-1317 (BAR allocs; struct resource *res local-only), 1324-1335 (leaking ENXIO returns), 1353-1355 (mn_reset failure returns success), 1386-1389 (ng_make_node_common failure returns success), 1392-1396 (name-failure frees node, softc keeps dangling pointer, returns success), 1402-1411 (no device_detach)
  • Severity: Low (privileged attach-time/hardware-error paths; resource-exhaustion and dangling-pointer hygiene, no direct unprivileged trigger)
  • CVSS: CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:L
  • CWE: CWE-772 (protected resource not freed) / CWE-404 (improper shutdown) / CWE-252 (unchecked return)
  • Confidence: certain (plain code reading)

Summary

mn_attach violates attach error-path symmetry in five distinct ways:

  1. BAR struct resource * handles are discarded. Both memory BAR allocations use a local res (if_mn.c:1302, :1311); only rman_get_virtual()/rman_get_start() are saved into the softc (:1307-1308, :1316-1317). The resource handles themselves are never stored, so they can never be bus_release_resource'd β€” on the success path they are held forever, and on every error return below they leak.

  2. Each early ENXIO leaks everything allocated before it: second-BAR failure leaks BAR0 (:1311-1315); IRQ-alloc failure leaks both BARs (:1324-1327); bus_setup_intr failure leaks both BARs plus the IRQ (:1332-1335). Failed attaches can be repeated (rescan, slot churn) and accumulate leaked bus resources.

  3. Failure returned as success. When the controller fails the PCI bus-master test, mn_reset returns 0 and attach does if (!u) return (0); (:1353-1355) β€” the device reports attach SUCCESS while non-functional, with the interrupt live and no netgraph node. Likewise ng_make_node_common failure prints and return (0) (:1386-1389).

  4. Name-failure path frees the node but leaves sc->node dangling (:1392-1396): ng_rmnode + ng_unref drop the creation reference (node refs β†’ 0 β†’ kfree) β€” note ngmn_shutdown is a no-op returning EINVAL (if_mn.c:280-285) so ng_cutlinks never runs β€” and the softc (still referenced by device_set_softc, interrupts live) keeps pointing at freed memory forever. Returns success (0) on top.

  5. No device_detach method at all (:1402-1411): IRQ teardown, resource release, softc free and netgraph node removal are impossible; hot-unplug or module unload leaks the softc, both BARs, the IRQ and the node.

Threat

Attacker relevance is indirect: repeated failed attaches (card mis-seated / bus-master-disabled slot / IRQ exhaustion) leak kernel bus resources (CWE-772), and the dangling sc->node (item 4) is a latent UAF pointer that future code paths touching sc->node would dereference. Requires the mn hardware and privileged (re)scan operations β€” hence Low.

Exploit / PoC

No runnable PoC beyond source inspection is possible on the audit guest (no card, driver not built β€” see run.log / env_guest.txt). Deterministic source-level demonstration: grep -n "bus_release_resource" if_mn.c β†’ no matches; grep -n "device_detach" if_mn.c β†’ no matches; the five code sites cited above.

Retain both BAR handles in the softc and release them (plus the IRQ) on every error path; return ENXIO on mn_reset/ng_make_node_common failure; on name failure set sc->node = NULL after destroying the node and return ENXIO; add a device_detach implementing the inverse of attach. See fix.diff for the minimal resource/return-value half (full detach requires lifecycle work out of scope for a minimal patch).

VERDICT.md
↓ download raw

DF-4343 VERDICT

Status: inconclusive on this guest (defect is static/plain-code) reproduced: 0 Β· impact on this guest: none Β· confidence: certain

All five defects are verifiable by direct source reading and greps; nothing depends on runtime hardware behavior:

  • res locals at if_mn.c:1302 / :1311 are never stored in struct softc (fields m0v/m0p/m1v/m1p hold only virtual/physical values, if_mn.c:1307-1308, :1316-1317); grep -n bus_release_resource sys/dev/netif/mn/if_mn.c β†’ no matches (resources unreleasable by construction).
  • Early returns at :1314, :1326, :1334 discard previously allocated resources.
  • :1353-1355 if (!u) return (0); β€” mn_reset failure reported as attach success.
  • :1386-1389 ng_make_node_common failure β†’ return (0).
  • :1392-1396 name failure: ng_rmnode + ng_unref free the node (refs 1β†’0 via the no-op ngmn_shutdown at if_mn.c:280-285, which never calls ng_cutlinks), leaving sc->node dangling in the still-live softc, then return (0).
  • :1402-1411 device_methods contains no device_detach.

Guest verification attempt (see run.log): no 0x110a PCI device, driver not built (optional mn netgraph), kldload if_mn ENOENT β€” attach paths cannot be exercised at runtime on this guest; classification inconclusive for the reproduction while the defect itself is certain from source.

Fix: fix.diff (git apply --check clean): retain both BAR handles in the softc (mem0, mem1), release them + the IRQ on every error path, return ENXIO on mn_reset / ng_make_node_common / ng_name_node failures, NULL the node pointer after destroying it. A full device_detach is additionally recommended upstream but is intentionally out of the minimal patch.

Files

README.md, VERDICT.md, run.sh, run.log, env_guest.txt, fix.diff, verdict.json, manifest.json (no runtime trigger exists for this class; source-level citations are the demonstration).

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

No baseline possible on this guest (hardware absent). fix.diff is line-accurate (git apply --check clean) and restores error-path symmetry for every cited site except the still-recommended full device_detach.

findings/poc/DF-4343/fix.diff
↓ fix.diffper-fix-DF-4343

Confirmed kernel references

Detail

Evidence (decisive lines)

README.md (five cited sites); VERDICT.md; run.log (guest greps: 0 releases / 0 detach; hardware absent); fix.diff (git apply --check OK)

PoC changes

no runtime trigger exists for this class; source citations + guest greps are the demonstration

Verified recommended fix

Retain both BAR resource handles in softc, release them + IRQ on every error path, return ENXIO on mn_reset/node-creation/name failures and NULL sc->node after destroying it; add device_detach (fix.diff carries the minimal half)

Verdict

Static, deterministic defect class (attach error-path symmetry); runtime paths unreachable on the audit guest (no Munich32X PCI device, driver 'optional mn netgraph' not built, kldload ENOENT). Verified from source: both BAR struct resource handles are stored only in the local 'res' and discarded (if_mn.c:1302,1311) so they can never be released; the ENXIO returns at 1314, 1326, 1334 leak every previously allocated resource; mn_reset failure and ng_make_node_common failure return 0 = attach success (1353-1355, 1386-1389); the ng_name_node failure path frees the node (ng_rmnode+ng_unref, refs 1->0 because ngmn_shutdown is a no-op returning EINVAL) while sc->node keeps the dangling pointer and attach still reports success (1392-1396); there is no device_detach at all (1402-1411). Guest-side grep confirmation in run.log: 0 bus_release_resource, 0 device_detach in the file.