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

UAF in add_bw_upcall: mfc pointer used after mroute_token released across blocking kmalloc

Summary

add_bw_upcall(:2285) captures mfc under token, releases token(:2301), kmalloc(M_INTWAIT blocks)(:2304), re-acquires token(:2319), writes through stale mfc(:2321-2322). Concurrent del_mfc(:1117) or MRT_DONE(:661) frees mfc during gap. Write to freed heap + dangling bm_mfc deref later. Root (mrouter socket) but kernel-scope.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0306 Β· 5 files
FileTypeDescriptionSize
VERDICT.md verdict source-trace confirmed UAF, root-only path 2.7 KB ↓ raw
README.md readme status explanation 787 B ↓ raw
fix.diff suggested-fix hold mroute_token across kmalloc 1.4 KB 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 status explanation
↓ download raw

DF-0306 PoC β€” UAF in add_bw_upcall

Status: REAL (source-trace confirmed), not reproduced at runtime

The bug is a genuine use-after-free confirmed by source trace of sys/net/ip_mroute/ip_mroute.c:2285-2326. It is not compiled into the default GENERIC kernel (options MROUTING required) and is root-only (requires SYSCAP_NONET_RAW for the raw IGMP socket needed by MRT_INIT).

No runtime PoC is provided because: 1. The code is not in the default kernel. 2. The race window is the M_INTWAIT kmalloc duration β€” too narrow to reliably win without memory-pressure grooming. 3. The entire multicast routing API requires root.

Fix

See fix.diff β€” holds mroute_token across the kmalloc to prevent concurrent del_mfc()/MRT_DONE from freeing mfc.

VERDICT.md verdict source-trace confirmed UAF, root-only path
↓ download raw

DF-0306 β€” UAF in add_bw_upcall: mfc pointer used after mroute_token released

Verdict: REAL (source-trace confirmed) β€” root-only path, not unpriv-escalatable

Mechanism

add_bw_upcall() in sys/net/ip_mroute/ip_mroute.c:2285-2326:

2285: lwkt_gettoken(&mroute_token);
2286: mfc = mfc_find(src, dst);          // captures mfc pointer
...
2301: lwkt_reltoken(&mroute_token);       // ← releases token
2304: x = kmalloc(sizeof(*x), M_BWMETER, M_INTWAIT);  // can block
...
2319: lwkt_gettoken(&mroute_token);       // re-acquires token
2320: x->bm_mfc = mfc;                   // ← stale mfc write
2321: x->bm_mfc_next = mfc->mfc_bw_meter; // ← stale mfc deref
2322: mfc->mfc_bw_meter = x;             // ← stale mfc write

During the token-released gap (lines 2301β†’2319), a concurrent del_mfc() or MRT_DONE can free mfc. The subsequent writes through the stale mfc pointer are a use-after-free (write to freed heap + dangling pointer installation).

Privilege requirement

The multicast routing API (MRT_INIT and all subsequent MRT_* setsockopts) requires a raw IGMP socket, which requires SYSCAP_NONET_RAW (root). See: - sys/netinet/raw_ip.c:473 β€” caps_priv_check(ai->p_ucred, SYSCAP_NONET_RAW) - sys/net/ip_mroute/ip_mroute.c:371 β€” if (so != ip_mrouter && sopt->sopt_name != MRT_INIT) return EPERM; - sys/conf/files:net/ip_mroute/ip_mroute.c optional mrouting β€” not even compiled into GENERIC

This is a valid hard blocker for unprivileged escalation: the write is reachable only from an already-root context (a multicast routing daemon). root→kernel is game-over by definition.

Reproduction status

  • Source trace: confirmed β€” the UAF pattern is unambiguous.
  • The code is not compiled into the default GENERIC kernel (requires options MROUTING).
  • Even with MROUTING, the race window is the M_INTWAIT kmalloc duration (microseconds unless under memory pressure), making reliable triggering very difficult without memory-pressure grooming.
  • Not testable from an unprivileged user under any condition.

Fix

fix.diff β€” hold mroute_token continuously across the kmalloc, matching the existing pattern at ip_mroute.c:1055 (add_mfc does the same: gettoken β†’ kmalloc M_INTWAIT β†’ reltoken). Also switch to M_NULLOK so failure is handled gracefully.

Impact

root→kernel UAF write. In a deployment where mrouted/pimd runs as root, a local attacker controlling the mrouter daemon (or racing it from root) could corrupt kernel heap. Realistic impact ceiling: root-operated daemon compromise → kernel privilege escalation beyond the daemon's sandbox. Low practical risk since root→kernel is already high-impact.

Fix verification

not_testable

compile validated

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. add_bw_upcall mfc UAF across M_INTWAIT kmalloc gap. ip_mroute not in GENERIC, root-only.