# DF-4235 — rl(4): every RX-error frame triggers a full adapter re-init under the ifnet serializer (remote per-frame DoS amplifier)

**File:** `sys/dev/netif/rl/if_rl.c` (pass 1 verification — first finding for this file)
**Severity:** Low (single-NIC remote availability degradation)
**Status:** source-certain; runtime inconclusive on the guest (QEMU's
rtl8139 model cannot inject RX_ERR frames — it accepts every frame with ROK,
so the error branch cannot be staged)

## The bug

`rl_rxeof()` (`if_rl.c:1028-1032`):

```c
if ((rxstat & RL_RXSTAT_RXOK) == 0) {
    IFNET_STAT_INC(ifp, ierrors, 1);
    rl_init(sc);          /* full adapter reset, in interrupt context */
    return;
}
```

Any inbound frame the 8139 flags bad (CRC error, runt, alignment, FIFO
overflow … — all remotely generatable by sending corrupted frames on the
wire) costs a **complete** `rl_init()`: `rl_stop()` (TX quiesce + free all
pending TX mbufs), full register reprogram, `rl_setmulti()` (TAILQ walk +
CRC32 per multicast entry), `mii_mediachg()` (PHY reprogram through MDIO
bit-banging with `DELAY(1)` loops — hundreds of PIO reads/writes on 8129
class parts), and a fresh `callout_reset` — all inside the interrupt (or
ifpoll) context while holding the interface serializer. At 100 Mbit/s line
rate a remote attacker can deliver ~148k minimum-size corrupted frames/s;
each one pays the full re-init and drops every co-pending frame, so a
trivially cheap packet stream keeps the interface permanently down/cycling
(`rl_intr` RX_ERR → `rl_rxeof` → `rl_init` → repeat). Note `RL_ISR_SYSTEM_ERR`
additionally arms the up-to-10 ms `rl_reset()` busy-wait (`if_rl.c:690-703`,
`RL_TIMEOUT=1000` × `DELAY(10)`), also under the serializer.

Sibling drivers moved to "count, skip descriptor, continue" for ordinary RX
errors decades ago; rl still hard-resets per frame.

## Fix

`fix.diff`: on ordinary per-frame RX errors just account + advance
(keep the re-init only for FIFO-overflow / system-error class conditions,
which the ISR path already handles via `RL_ISR_SYSTEM_ERR`).

## Live evidence gathered (supporting, this pack)

The guest **does** emulate an rtl8139 (`dfbsd-qemu/vm_rl.sh` temp launcher),
so the driver's normal RX/TX paths were exercised live for this audit:
attach, ~1250 packets of DNS traffic through `rl_rxeof`/`rl_encap`, promisc,
media change, BPF, 600 down/up cycles — zero memory-safety events (see
`rl_live_test.sh`, `rl_repro.sh`, `guest_env.txt`, and the DF-4236 pack for
the churn behavior). That live run doubles as negative evidence for the
length-trust analysis: DFly's `m_devget()` chunks arbitrary lengths and the
`uint16_t` `cur_rx` arithmetic wraps exactly at `RL_RXBUFLEN` (65536), so
`rl_rxeof` is memory-safe even against a lying device — the only defect on
that path is this Low-severity re-init amplifier.
