RX ring collapse: constant-condition ternary links all 64 RX descriptors (software and hardware next pointers) to descriptor 0
Summary
wb_list_rx_init computes nexti = (WB_RX_LIST_CNT - 1) ? 0 : i + 1 - the condition is the compile-time constant 63, not i == 63, so nexti is always 0. Every descriptor's software wb_nextdesc and hardware wb_next point at descriptor 0: the intended closed 64-ring becomes a 1-deep self-ring. The chip completes desc[0], follows next back to desc[0], finds it unrecycled and suspends RX -> per-frame receive-engine restart; 63 of 64 pre-allocated RX buffers are unreachable dead state. A DragonFly-port typo (the TX twin in the same file is correct; FreeBSD 4.11 has the right form). Deterministic logic harness: DFly ring reaches 1/64 vs FreeBSD 64/64. One-token fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4267 Β· 14 files| File | Type | Description | Size | |
|---|---|---|---|---|
| dfwb3_rig.c | β | 40.9 KB | view raw | |
| Makefile | β | 105 B | β download | |
| kld_run.sh | β | 2.8 KB | view raw | |
| kld_build.log | β | 1.1 KB | view raw | |
| run.kld.log | β | 1.7 KB | view raw | |
| run.kld.dmesg.log | β | 4.5 KB | view raw | |
| run.kld_fixed.log | β | 4.8 KB | view raw | |
| fix_validated.diff | β | 2.2 KB | view raw | |
| env.kld.txt | β | 491 B | view raw | |
| wb_logic.c | β | 4.2 KB | view raw | |
| logic_run.log | β | 719 B | view raw | |
| run.sh | β | 111 B | view raw | |
| VERDICT.md | β | 4.0 KB | β raw | |
| verdict.json | β | 3.7 KB | view raw |
VERDICT β DF-4267 (RX ring collapse in wb_list_rx_init, if_wb.c:909)
Status: reproduced (deterministic, production code) β fix validated: fixed.
Method
Same evidence class as the accepted DF-4266 verification: the guest has no
W89C840F NIC, but device wb is built into X86_64_GENERIC, so the driver's
real static functions live in the running kernel. The rig
(dfwb3_rig.c, built -Werror clean; struct-layout cross-checked against
the kernel's own disassembly β see DF-4266's pack) resolves wb_init from
/boot/kernel/kernel via nm(1), fabricates the proven post-attach softc,
and dispatches the kernel's own wb_init() β its inlined
wb_list_rx_init builds the ring exactly as production does at every
wb_init call (boot, SIOCSIFFLAGS, every babble reset, watchdog...).
The ring that wb_init leaves behind IS the finding's subject.
Baseline β stock kernel #0 (Jul 2 2026), run.kld.dmesg.log
- Hardware links: all 64
wb_rx_list[i].wb_next==vtophys(&wb_rx_list[0])(0x2ec4b100 in that boot). A closed ring would link iβi+1 and 63β0.=> 64/64 hardware wb_next words point at descriptor 0. - Software links: walk from
wb_rx_headviawb_nextdesc:distinct descriptors reachable = 1 / 64 (returned to a visited descriptor after 1 hops). - TX contrast (
:878twin, correct):128 / 128. - Behaviour: crafted completed frame (OWN=0, RXCMP|FIRST|LAST, len 64)
in slot 0, processed by the fixed-OWN comparator (the stock rxeof's
inverted loop is DF-4266 and would mask frame processing; the comparator
changes ONLY that comparison): frame delivered (
delivered=1), thenhead==chain0:1 head==chain1:0β the ring re-enters descriptor 0. Repairing only the 64wb_nextdescwords (simulating the one-token fix): the identical state delivers and advanceshead==chain1:1β the collapse is the only difference. - Chip view:
MMIO WB_RXADDR == vtophys(&wb_rx_list[0])always; the chip fetches desc 0, completes, followswb_nextback to desc 0, finds it unrecycled and suspends β per-frame RX restart (wb_intr:1137,wb_rxeoc:1030-1039rewrites RXADDR and pokes RXSTART); with DF-4266's inversion also present, the driver additionally re-arms under the chip.
Impact: deterministic RX-throughput collapse / interrupt churn (availability DoS) on W89C840F/Compex RL100-ATX hosts β the ring is 1-descriptor deep regardless of traffic; 63/64 pre-armed RX buffers (64 MGETHDR mbufs + 256 KB of contigmalloc buffers) are permanently unreachable. Severity: availability bug (High per DB row; no memory corruption β DF-4268 tracks the corruption family and was NOT confirmed, see its pack).
Fix validation β kernel #1 (Oct 14 2026, same tree + fix_validated.diff)
fix_validated.diff (combined DF-4267+DF-4268+DF-4270) applied inside the
guest's /usr/src; make -j6 nativekernel + installkernel (build log
line 18497 recompiles if_wb.c); rebooted into kernel #1; the identical rig
re-run (run.kld_fixed.log):
| observable | stock #0 | fixed #1 |
|---|---|---|
wb_rx_list[i].wb_next |
all == &list[0] | monotonic i+1 (β¦b110, β¦b190, β¦b210), 63β0 |
| software walk from head | 1 / 64 | 64 / 64 |
| head after processing slot 0 | chain[0] (stuck) | chain[1] (advances) |
| TX contrast | 128/128 | 128/128 (unchanged) |
fix_status: fixed (baseline_reproduced=1, patched_reproduced=0).
Rig artifacts / incidents
None for this scenario (no threads, no races): stock and fixed runs both SURVIVED with the guest clean. The rig bugs recorded in the sibling packs (DF-4268 toggle-thread exit, DF-4270 unguarded txeof dispatch) do not touch the 4267 scenario.
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: on the patched kernel the REAL wb_init builds a true closed ring (64/64 reachable, i+1 links, head advances past slot 0); all baseline defect markers gone
run.kld_fixed.log; fix_validated.diff; VERDICT.md 'Fix validation' table
Confirmed kernel references
Detail
Evidence (decisive lines)
run.kld.dmesg.log ('=> 64/64 hardware wb_next words point at descriptor 0', 'distinct descriptors reachable = 1 / 64', 'TX contrast ... 128 / 128', '*** DF-4267 CONFIRMED (behavioural) *** ... head==chain1:0', A/B with repaired links 'head==chain1:1'); run.kld_fixed.log (fixed kernel: monotonic wb_next links, '64 / 64', 'head==chain1:1'); VERDICT.md table
PoC changes
Replaced the seed's pure-logic harness verdict ('kernel-level reproduction impossible') with the DF-4266 production-handler KLD dispatch rig: the REAL wb_init() builds the ring over a fabricated post-attach softc; added the fixed-OWN comparator (isolates ring topology from DF-4266's inverted loop), the distinct-descriptor walks, the TX-contrast walk, the one-token A/B link repair, and the RXADDR MMIO check. Fix validation added (combined 3-fix kernel).
Verified recommended fix
nexti = (i == WB_RX_LIST_CNT - 1) ? 0 : i + 1; (mirror the TX-side ternary at if_wb.c:878) β validated as fix_validated.diff hunk 1
Verdict
Reproduced on production code: dispatched the running kernel's own wb_init() (its inlined wb_list_rx_init is the defective code, if_wb.c:909-911) from the DF-4266 KLD rig; the production post-init ring shows ALL 64 hardware wb_next words == vtophys(&wb_rx_list[0]) and a software wb_nextdesc walk reaching 1/64 distinct descriptors (TX twin at :878: 128/128, confirming the one-token port typo). Behaviourally, a chip-completed frame processed in slot 0 leaves wb_rx_head AT slot 0 β the driver can never advance past descriptor 0, the chip suspends RX after every frame (per-frame receive-engine restart via wb_intr:1137/wb_rxeoc:1030, RXADDR always &list[0]), and 63/64 pre-armed RX buffers are permanently unreachable: deterministic RX-throughput collapse/DoS on W89C840F-equipped hosts. Fix validated on a rebuilt kernel (kernel #1, fix_validated.diff): wb_next links become i+1 with 63->0, software walk 64/64, head advances to chain[1] β every defect marker gone.
No comments yet.