# DF-3904 — sk_rxeof() Rx walk has no work bound (DF-3761 family, sk(4) instance)

**File:** `sys/dev/netif/sk/if_sk.c` (pass 2, GLM 5.3)
**Hardware-gated:** the audit guest has no SysKonnect SK-98xx/Yukon NIC, so
the driver path cannot be exercised at runtime. Source-level certainty only;
status `inconclusive` per family convention (identical treatment as the
alc(4) original DF-3761).

## The bug (source)

`sk_rxeof()` (`sys/dev/netif/sk/if_sk.c:1803-1888`) processes completed RX
descriptors in an **unbounded** `for (;;)` loop:

- only exit conditions are (a) the next descriptor still has
  `SK_RXCTL_OWN` set (`:1833-1837`) — i.e. the walker caught up with the
  NIC — or (b) nothing else: no packet counter, no budget.
- every processed descriptor is immediately handed back to the NIC with
  ownership via `sk_newbuf()`/repost (`:1873`, `:1862`, `:1875`), so under
  a line-rate remote flood the BMU can re-complete descriptors **behind
  the walker's back**; after one lap (256 descriptors) the loop reaches
  index 0 again, finds it completed, and keeps going — indefinitely.
- the walk runs inside `sk_intr()` (`:2212-2221`) which holds the ONE
  card-global `sc->sk_serializer` for the whole interrupt
  (`bus_setup_intr(..., &sc->sk_serializer)` at `:1514`), on **both
  ports** of a dual-port card.

Consequence (on sk hardware): a remote unauthenticated flood pins the
interrupt CPU and the card serializer forever — RX livelock / remote DoS,
starving softclock (including the very `sk_tick` DF-3903 is about),
netisr, and the other port's TX/RX on the same serializer. This is the
same defect class as DF-3761 (alc(4)); the sibling driver msk(4) bounds
the identical walk with `sc->msk_process_limit`
(`sys/dev/netif/msk/if_msk.c:3225`, tunable `mskc.process_limit`),
proving the fix shape in-tree.

## Why not runtime-verified

No SysKonnect PCI NIC exists on the audit QEMU guest (`pciconf -l` has no
0x10b3/0x1148 Yukon/GEnesis IDs), so `sk_rxeof` is unreachable at runtime.
The unbounded loop is however directly visible in source and requires no
hardware state to reason about. `verdict.json` records `inconclusive`
(matching how DF-3761/3806/3850-family hardware-gated findings were
persisted), reproduced=0.

## Fix

`fix.diff`: add an `SK_RX_PROC_MAX` (64) packet budget to `sk_rxeof`,
saving the resume index (`cd->sk_rx_prod = i`) before breaking — exactly
what the loop already does at the OWN-bit exit (`:1835`), so the
interrupt re-entry protocol is preserved. Mirrors msk(4)'s
`msk_process_limit`.
