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

Unsynchronized sc->inq/outq between hard ISR and netgraph forward: ifqueue corruption / UAF

Summary

bt3c_intr hard-ISR(:771) -> bt3c_receive IF_ENQUEUE(&sc->inq)(:939). bt3c_swi_intr(SWI_TTY:963) -> ng_send_fn -> bt3c_forward IF_DEQUEUE(&sc->inq)(:1017). IF_ENQUEUE/DEQUEUE macros(if_var.h:484-510) are LOCK-FREE linked list manipulation. attach(:609-675) inits NO ifqueue lock. Hard ISR explicitly outside netgraph node serialization. Hard IRQ preempts SWI -> ISR IF_ENQUEUE mid-IF_DEQUEUE -> list corruption, ifq_tail/ifq_head dangling at freed mbuf -> UAF. Same pattern outq(:566 vs :1060/:1081). Remote-ish BT RF trigger but gated on rare 3CRWB609 PCMCIA hardware. Fix: move IF_ENQUEUE to SWI or spinlock all queue ops.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0533 Β· 9 files
FileTypeDescriptionSize
build.sh build-script reports absence of ng_bt3c module/PCMCIA 330 B view raw
run.sh run-script probes driver/bus absence 451 B view raw
run.log run-log reachability probe: no module, no PCMCIA, no BT option 662 B view raw
env.txt environment uname, module/bus/option absence 304 B view raw
fix.diff suggested-fix add sc_lock spinlock; wrap all IF_*QUEUE sites (var.h + pccard.c); applies cleanly 3.0 KB view raw
VERDICT.md verdict full source trace + reachability + fix rationale 3.3 KB ↓ raw
README.md readme evidence pack index 1.5 KB ↓ 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 evidence pack index
↓ download raw

DF-0533 β€” bt3c hard-ISR vs SWI unsynchronized inq/outq race (UAF)

Verdict: LATENT on this guest (source bug real; not runtime-exercisable). Fix authored (fix.diff, applies cleanly; not_testable β€” no PCMCIA HW).

Bug

ng_bt3c_pccard.c registers a hard ISR (bt3c_intr β†’ bt3c_receive) that does IF_ENQUEUE(&sc->inq, …) (:939) and an SWI handler (bt3c_swi_intr β†’ bt3c_forward) that does IF_DEQUEUE(&sc->inq, …) (:1017). IF_*QUEUE macros (net/if_var.h:484-510) are lock-free linked-list ops, and attach initialises no lock for inq/outq. A hard IRQ landing mid-IF_DEQUEUE corrupts the list β†’ dangling ifq_head/ifq_tail β†’ UAF. Same shape on outq (:566 vs :1060/:1081).

Reachability

Latent on this guest. The driver is optional netgraph7_bluetooth_bt3c (sys/conf/files:1669); there is no ng_bt3c.ko shipped, no bt3c symbols in the running kernel, no PCMCIA/pccard bus in QEMU, and the 3Com 3CRWB6095 card it drives is absent. So the race is dead code here β€” a real defect that would manifest on real hardware.

Fix

fix.diff adds a struct spinlock sc_lock to bt3c_softc (ng_bt3c_var.h), spin_inits it in attach, and wraps every IF_ENQUEUE/IF_DEQUEUE/IF_PREPEND site (inq + outq) with spin_lock/spin_unlock, serialising the ISR producer against the SWI/netgraph consumers. Applies cleanly; not build-validated (needs PCMCIA headers/HW).

See VERDICT.md for the full line-cited trace.

VERDICT.md verdict full source trace + reachability + fix rationale
↓ download raw

DF-0533 β€” bt3c hard-ISR vs SWI unsynchronized inq/outq race (UAF): LATENT

Verdict: NOT REPRODUCED on this guest (LATENT). Source bug REAL; fix authored, applies cleanly; not build/runtime-testable here (no PCMCIA hardware + module not shipped).

SOURCE TRACE (bug is real)

Driver: sys/netgraph7/bluetooth/drivers/bt3c/ng_bt3c_pccard.c (3Com 3CRWB6095 PCMCIA Bluetooth card)

  • bt3c_pccard_attach (:609-671):

    • bus_setup_intr(dev, sc->irq, 0, bt3c_intr, sc, ...) [:635] -> hard ISR
    • register_swi_mp(SWI_TTY, bt3c_swi_intr, ...) [:643] -> SWI handler
    • sc->inq.ifq_maxlen = sc->outq.ifq_maxlen = ...; [:668] NO ifqueue lock / spinlock is initialised for inq or outq.
  • bt3c_intr (hard ISR, :749) -> bt3c_receive (:786) -> on a complete packet: IF_ENQUEUE(&sc->inq, sc->m); [:939] (also IF_QFULL/IF_DROP on inq at :930/:934.)

  • bt3c_swi_intr (:963) -> ng_send_fn(..., &bt3c_forward, ...) [:973] -> bt3c_forward (:1005) drains the queue from SWI/netgraph context: IF_DEQUEUE(&sc->inq, m); [:1017, :1027] bt3c_send (:1042) does IF_DEQUEUE/IF_PREPEND on outq [:1060, :1081]; bt3c_rcvdata (netgraph hook) does IF_ENQUEUE on outq [:566].

  • IF_ENQUEUE / IF_DEQUEUE / IF_PREPEND (net/if_var.h:484-510) are LOCK-FREE doubly-linked-list manipulations of ifq_head/ifq_tail. There is no serializer between the hard ISR (which preempts SWI) and the SWI dequeue. A hard IRQ landing mid-IF_DEQUEUE corrupts the list -> ifq_tail/ifq_head dangle at a freed mbuf -> use-after-free. (Same shape on outq between rcvdata and bt3c_send.)

REACHABILITY ON THIS GUEST (latent)

  • ng_bt3c_pccard.c is optional netgraph7_bluetooth_bt3c (sys/conf/files:1669) and is built as module ng_bt3c.ko via a PCMCIA (pccard) driver. There is NO ng_bt3c.ko in /boot/kernel on this guest, no bt3c symbols in the running kernel (nm count = 0).
  • The driver requires a 3Com 3CRWB6095 PCMCIA card. QEMU does not emulate PCMCIA/pccard; devinfo shows no pccard/cardbus/cbb bus. So the driver cannot attach and no bt3c interrupts can occur.
  • => The race is DEAD CODE on this guest. It is a real latent defect that would manifest on real hardware (or a PCMCIA-emulating harness). This is a valid "genuinely not reachable on this kernel AND no harness can exercise it" case: the primitive is proven at the source level (lock-free IF_*QUEUE macros with a preempting producer), but no live trigger exists here.

FIX

fix.diff adds a struct spinlock sc_lock to bt3c_softc (ng_bt3c_var.h), inits it in attach (spin_init), and wraps every IF_ENQUEUE/IF_DEQUEUE/IF_PREPEND site (inq in bt3c_receive + bt3c_forward; outq in bt3c_rcvdata + bt3c_send) with spin_lock/spin_unlock. The spinlock is acquireable from the hard ISR filter context, serialising the producer (ISR) against the consumers (SWI/netgraph). git-apply-able; applies cleanly. NOT build-validated on this guest (the module requires pccard bus headers / hardware to build & exercise).

NOT TESTABLE

fix_status = not_testable: cannot build/exercise ng_bt3c on a guest without PCMCIA. The diff applies and the change is correct-by-inspection against the net/if_var.h IF_* macro definitions.

Fix verification

not_testable

compile validated

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. bt3c ISR/SWI IF_ENQUEUE/IF_DEQUEUE lock-free race -> UAF. No PCMCIA HW, ng_bt3c not shipped.