struct bridge_ifinfo leaked on every span-port delete (bridge_ioctl_addspan allocates it; bridge_delete_span frees only the bif)
Summary
bridge_ioctl_addspan allocates bif_info (:1823) and stores it in bif->bif_info (:1828); bridge_delete_span frees only the bif (:1156), orphaning ~114 bytes of M_DEVBUF per spanport add/del cycle - via both the ioctl path and ifnet-detach. MEASURED on stock guest: devbuf in-use 3.12M -> 5.40M (+2.28MB) over 20000 cycles; zero growth on the fixed kernel. Root-gated unbounded kernel heap exhaustion for hosts whose automation cycles mirror ports. Fix: kfree(bif->bif_info) alongside the bif.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3279 Β· 10 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 635 B | β raw | |
| verdict.json | β | 2.1 KB | view raw | |
| env.txt | β | 743 B | view raw | |
| build.log | β | 131 B | view raw | |
| fix.diff | β | 706 B | view raw | |
| run.sh | β | 99 B | view raw | |
| run.log | β | 829 B | view raw | |
| VERDICT.md | β | 2.0 KB | β raw | |
| run_fixed.log | β | 674 B | view raw | |
| span_leak.c | β | 1.6 KB | view raw |
DF-3279 β struct bridge_ifinfo leaked on every span-port delete
What
bridge_ioctl_addspan() allocates a bridge_ifinfo for the span bif
(if_bridge.c:1823-1828), but bridge_delete_span() frees only the
bif (if_bridge.c:1155-1156) β the bif_info is never freed. Every
spanport add/del cycle leaks ~114-120 bytes of M_DEVBUF kernel memory.
Reproduce (guest, as root)
cd /root/poc/df-3279 cc -O -o span_leak span_leak.c # create bridge0 + tap0 first ./span_leak 20000 vmstat -m | grep devbuf
Expected
devbuf in-use grows by ~2.3 MB after 20000 cycles (measured: 3.12M -> 5.40M, i.e. ~114 bytes/cycle).
DF-3279 β VERDICT
REPRODUCED β deterministic kernel memory leak (root-gated).
Evidence (baseline kernel, before fix)
$ vmstat -m | grep -E "^ *devbuf" (before)
devbuf 24.6K 3.12M 0 390M 49.1K
$ ./span_leak 20000 (20000 spanport add/del cycles)
$ vmstat -m | grep -E "^ *devbuf" (after)
devbuf 44.2K 5.40M 0 390M 88.2K
Delta: +2.28 MB / 20000 cycles β 114 bytes leaked per cycle β
matching sizeof(struct bridge_ifinfo) plus allocator rounding.
Root cause
bridge_ioctl_addspan() (if_bridge.c:1823):
bif_info = kmalloc(sizeof(*bif_info), M_DEVBUF, M_WAITOK | M_ZERO);
assigned to bif->bif_info (if_bridge.c:1828). Nothing else
references it (span bifs are never passed to bridge_delete_member;
the span branch of bridge_ioctl_gifs() at if_bridge.c:1482-1493
doesn't touch bif_info). bridge_delete_span() kfrees only bif
β the bif_info is orphaned. Both the ioctl path and the
ifnet-detach path (bridge_ifdetach_dispatch, if_bridge.c:1900-1904)
go through bridge_delete_span, so both leak.
Impact
Unbounded kernel heap exhaustion by repeated BRDGADDS/BRDGDELS
cycles β requires root (both ioctls are BC_F_SUSER-gated), so this
is a resource-leak bug (Low) rather than a privilege issue. A
long-running host where automation adds/removes span ports (e.g. per-
session port mirroring) slowly bleeds unrecoverable kernel memory
until reboot.
Fix validation
fix.diff (free bif_info in bridge_delete_span) applied with the
combined patch; on the rebuilt kernel the same 20000-cycle loop left
devbuf in-use unchanged (see run_fixed.log).
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
fixedFixed kernel: same 20000-cycle loop leaves devbuf in-use unchanged (266K -> 266K) vs +2.28MB on baseline.
findings/poc/DF-3279/run_fixed.log
Confirmed kernel references
Detail
Evidence (decisive lines)
['run.log: vmstat -m devbuf before/after on baseline and fixed kernels', 'fix.diff: kfree(bif->bif_info) in bridge_delete_span', 'run_fixed.log: zero growth over the identical 20000-cycle loop']
PoC changes
Written from scratch; needed
Verified recommended fix
free bif->bif_info in bridge_delete_span (bundled with the DF-3277 list-head fix)
Verdict
Deterministic kernel heap leak: bridge_ioctl_addspan() allocates a bridge_ifinfo (if_bridge.c:1823-1828) that bridge_delete_span() never frees (frees only the bif, if_bridge.c:1155-1156). Measured on the stock guest: devbuf in-use grew 3.12M -> 5.40M (+2.28MB) over 20000 spanport add/del cycles = ~114 bytes/cycle. On the rebuilt kernel with bif_info freed: 266K -> 266K, zero growth.
No comments yet.