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

ng_fec_rmnode infinite loop when member interface vanished: dangling ptr + unkillable loop

Summary

ng_fec_rmnode(:1224-1229): while(!TAILQ_EMPTY) p=TAILQ_FIRST ksprintf(ifname,%s,p->fec_if->if_xname) ng_fec_delport(priv,ifname). delport re-resolves ifunit(:433) returns ENOENT(:434-439) WITHOUT removing port from TAILQ if interface destroyed. Loop never terminates. p->fec_if dangling -> if_xname UAF. Same as DF-0502(ng7). Fix: unlink+free directly in rmnode dont re-resolve.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0528 Β· 9 files
FileTypeDescriptionSize
trigger.sh trigger-source create node, add tap, destroy tap, shutdown -> loop 1.5 KB view raw
build.sh build-script 228 B view raw
run.sh run-script 216 B view raw
fix.diff suggested-fix unlink+free directly in rmnode, skip ifunit re-resolution 999 B view raw
VERDICT.md verdict source confirmation + DF-0529 blocker 2.6 KB ↓ raw
build.log build-log fix compile-validated RC=0 63 B view raw
env.txt environment 829 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
VERDICT.md verdict source confirmation + DF-0529 blocker
↓ download raw

DF-0528 β€” VERDICT

Verdict: SOURCE-CONFIRMED, NOT REACHABLE AT RUNTIME (blocked by DF-0529)

The bug (confirmed in source)

ng_fec_rmnode() (sys/netgraph/fec/ng_fec.c:1213) tears down the bundle by looping over member ports and calling ng_fec_delport() by interface name, which re-resolves the interface via ifunit():

// :1224-1229
while (!TAILQ_EMPTY(&b->ng_fec_ports)) {
    p = TAILQ_FIRST(&b->ng_fec_ports);
    ksprintf(ifname, "%s", p->fec_if->if_xname);   // UAF if iface already freed
    ng_fec_delport(priv, ifname);
}

ng_fec_delport() (:417) does:

// :433-439
bifp = ifunit(iface);
if (bifp == NULL) {
    kprintf("... doesn't seem to exist\n");
    return (ENOENT);          // returns WITHOUT removing the port from the TAILQ
}

If a member interface has already been destroyed (e.g. the admin destroyed a tap member, or the underlying NIC was detached), ifunit() returns NULL and delport returns ENOENT without unlinking the port. The while loop in rmnode therefore never makes progress β†’ infinite loop (kernel hang / soft-lockup). Additionally p->fec_if->if_xname is a use-after-free once the member ifnet has been freed. This is the same defect as the netgraph7 twin DF-0502.

Why it cannot be triggered at runtime on this guest

ng_fec_rmnode() runs when an ng_fec node is shut down β€” which requires a node to have been created first. But ng_fec_constructor() panics on every node creation (DF-0529), so no node is ever available to shut down. Verified empirically; the node is uncreatable even after DF-0529's documented fix.

Impact ceiling (latent)

Kernel hang / infinite loop in ng_fec_rmnode (local DoS), plus a use-after-free read on p->fec_if->if_xname. The UAF is a read (string format), not a controllable write.

Exploit chain

none β€” infinite-loop DoS + UAF read; not a write-capable primitive.

Fix validation

fix.diff replaces the delport-by-name loop with a direct unlink+free (avoiding the ifunit() re-resolution entirely):

while (!TAILQ_EMPTY(&b->ng_fec_ports)) {
    p = TAILQ_FIRST(&b->ng_fec_ports);
    TAILQ_REMOVE(&b->ng_fec_ports, p, fec_list);
    kfree(p, M_NETGRAPH);
}
b->fec_ifcnt = 0;

Compiles cleanly (RC=0). fix_status = not_testable β€” the DF-0529 constructor panic prevents creating a node to shut down; compile-validated only, traced to close the cited path.

PoC changes

Wrote trigger.sh (create node, add tap, destroy tap, shutdown node β€” needs a DF-0529-fixed kernel), build.sh/run.sh, fix.diff. No upstream PoC.

Fix verification

not_testable

compile validated

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. ng_fec_rmnode infinite loop + UAF when member iface destroyed. Blocked by DF-0529.