# DF-4317 — VERDICT

**Status: hardware-gated → untested on this guest (no LGE NIC:
`ifconfig -l` → `vtnet0 lo0`). Source analysis certain; runtime likelihood
of the race, once traffic flows and clusters get shared, follows the
DF-1384 (nge twin) precedent: Low severity, local DoS / data-corruption
ceiling.**

## Root cause (path:line)

- `sys/dev/netif/lge/if_lge.c:685-688` — every RX jumbo mbuf wires
  `m_ext.ext_ref = lge_jref`; the mbuf layer calls it whenever the external
  cluster is shared (m_copym full-buffer copy, m_dup_pkthdr, BPF copies).
- `sys/dev/netif/lge/if_lge.c:801-814` — `lge_jref()`:
  - `:807` membership sanity check (fine),
  - `:810` **unlocked** read `entry->lge_inuse == 0` → panic, else
  - `:813` `atomic_add_int(&entry->lge_inuse, 1)` — the increment is atomic
    but the *check-then-act pair* is not serialized.
- `sys/dev/netif/lge/if_lge.c:819-841` — `lge_jfree()` correctly takes
  `sc->lge_jslot_serializer` (:833) around
  `atomic_subtract_int(&entry->lge_inuse, 1)` (:834) and the
  `SLIST_INSERT_HEAD(&sc->lge_jfree_listhead, entry, ...)` (:836-837) that
  recycles the slot **when the count hits 0**.
- `sys/dev/netif/lge/if_lge.c:777-794` — `lge_jalloc()` is serialized
  (:782) and pops from `lge_jfree_listhead` (:783-785).

Interleaving (CPU0 = lge_jref via shared mbuf, CPU1 = lge_jfree via original
mbuf):

```
CPU0: lge_jref(E): reads inuse == 1            (check passes, no lock)
CPU1: lge_jfree(E): [serializer] inuse 1->0; SLIST_INSERT_HEAD(free, E)
CPU0: lge_jref(E): atomic_add inuse 0->1        (E: on free list AND inuse)
CPU1: lge_jalloc(): [serializer] pops E -> new lge_newbuf RX descriptor
```

Consequences: two owners of one 9 KB jumbo cluster — the NIC DMAs received
frames into a buffer the stack is concurrently reading (data corruption /
cross-packet bleed), and the second eventual `lge_jfree` either panics
(`lge_jfree: buffer already free!`, :831) or double-inserts the slot,
corrupting `lge_jfree_listhead`.

This is the same defect DF-1384 established for nge(4)
(`nge_jref` unlocked check-then-add vs serialized `nge_jfree`), in lge's
copy of the Bill Paul jumbo-pool template. Only `lge_jref` is the unlocked
actor here; `lge_jalloc`/`lge_jfree` are correctly serialized.

## Why not reproducible on this guest

The race requires a Level-One LXT1001 NIC serving RX traffic whose jumbo
clusters get shared and freed concurrently. The audit guest is virtio-based
(`ifconfig -l` → `vtnet0 lo0`); the driver cannot even attach. The code shape
is driver-local and fully verifiable by inspection; the twin finding DF-1384
documents the same interleaving.

## Fix

`fix.diff` — serialize the check+increment in `lge_jref()` with
`sc->lge_jslot_serializer` (identical to the DF-1384 fix for nge_jref). No
recursion risk: lge_jref runs from mbuf code with no driver locks held;
lge_jfree only takes the same serializer (same thread cannot be inside both).
fix_status=not_testable (no lge hardware in guest).

## 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.
