# DF-4159 VERDICT — RX livelock in xe_intr() drop paths (not released to hardware)

**Status: untested (kernel/hardware level) — logic-model harness CONFIRMS the
loop divergence; runtime confirmation requires Xircom PCMCIA hardware which
does not exist in the QEMU guest.**

## Root cause (path:line)

`sys/dev/netif/xe/if_xe.c`, `xe_intr()`:

- `:742`  `while ((esr = XE_INB(XE_ESR)) & XE_ESR_FULL_PACKET_RX) {`
- `:756-759`  `if (len == 0) { IFNET_STAT_INC(ifp, iqdrops, 1); continue; }`  ← **no release**
- `:769-773`  `MGETHDR` failure → `continue;`                                   ← **no release**
- `:775-781`  `MCLGET` failure → `m_freem(mbp); ...; continue;`                 ← **no release**
- `:843`  `XE_OUTW(XE_DO, 0x8000);`  ← the only packet-release point, skipped by all three paths above

`XE_DO_SKIP_RX_PACKET` (0x8000) is the only mechanism that advances the card's
receive buffer past the current packet (`sys/dev/netif/xe/if_xereg.h:247-256`).
`XE_ESR_FULL_PACKET_RX` (ESR bit 0, `if_xereg.h:219`) is a *level* indication
of "at least one full packet received [and unreleased]". Consequently every
`continue` re-enters a loop whose condition is still true: the loop can never
terminate.

## Why I believe the register semantics (cross-validation)

1. Linux's driver for the identical silicon, `drivers/net/ethernet/xircom/
   xirc2ps_cs.c` (still maintained), executes at the end of **every** loop
   iteration — good packet, dropped packet (skb-alloc failure), or error
   packet:

       /* clear the received/dropped/error packet */
       PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */
       eth_status = GetByte(XIRCREG_ESR);

   The comment names "dropped" explicitly: skipping is mandatory on drop paths.

2. Old FreeBSD (10.3, last release shipping this driver) has the identical
   `continue`-without-skip structure — this is a shared, never-upstream-fixed
   bug in the 1999-era BSD driver, not DragonFly-local; DragonFly inherited
   and still ships it (X86_64_GENERIC contains `device xe`).

## Demonstrated evidence

`livelock_harness.c` (this pack) models the loop control flow verbatim with a
register file that implements the semantics above. Built and executed on the
audit guest (`DragonFly dfbsd 6.5-DEVELOPMENT #0 ... x86_64`, gcc 8.3):

- MODE 0 (code as written), normal packet → terminates, 1 skip write.
- MODE 0, len==0 → LIVELOCK (200000-iteration cap hit, 0 skip writes).
- MODE 0, MGETHDR-fail → LIVELOCK.
- MODE 0, MCLGET-fail → LIVELOCK.
- MODE 1 (fix applied), any path → terminates in 1 iteration.

See `run.log` (full output).

## Impact

`xe_intr()` is registered with `scp->ifp->if_serializer` (`if_xe.c:333-335`)
and `INTR_MPSAFE`; the livelock therefore spins in hard-interrupt context
**while holding the ifnet serializer forever**:

- every subsequent interface ioctl / ifnet operation on xe0 spins on the
  serializer;
- the netisr softcall path that would run `if_watchdog`/timers also needs the
  serializer → no recovery path exists in-kernel;
- the card keeps its IRQ asserted (RX packet still pending), so even a
  hypothetical loop exit re-enters immediately;
- net effect: permanent hard hang requiring power cycle — a local+remote DoS
  (remote peer sends one frame while an unprivileged local user has drained
  mbuf clusters so `MGETHDR`/`MCLGET(M_NOWAIT)` fail; or a crafted CRC-only
  frame yielding `RBC==4`, `len==0`).

Hardware-gated: triggering requires a Xircom CE2/CE3/CEM/RealPort PCMCIA
adapter (or compatible) — `device xe` is compiled into the stock
X86_64_GENERIC kernel but only attaches to actual PCMCIA hardware.

## Exploit chain

Not a corruption primitive — pure DoS. No escalation path identified (loop
writes nothing outside iqdrops counters and the fixed card registers).

## Fix validation

`fix.diff` adds `XE_OUTW(XE_DO, 0x8000);` before each of the three `continue`
statements (mirroring Linux's unconditional skip). Logic-model scenarios 5-6
(MODE 1) show the loop then terminates with the packet correctly released.
A full kernel-build validation was not performed: the modified path is
unreachable without Xircom PCMCIA hardware (driver attaches only on such
devices; the guest has none), so a built kernel could never exercise the
changed lines — the harness is the strongest available validation.

## Classification notes

- distinct from pass-1 DF-1410 (missing upper bound on `len` → heap overflow
  on copy): DF-4159 is about the *control flow* (packet release) on drop
  paths, present even for in-bounds lengths.
- `guest_uname`: recorded from the guest where the harness ran.

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