# DF-5453 VERDICT — reproduced (panic), fix validated (fixed)

## Finding

`kue_attach()` (sys/bus/u4b/net/if_kue.c:469-511) routes **all three** of its
failure branches through `goto detach; → kue_detach(dev);` (if_kue.c:508-510),
but two of them run while the embedded `usb_ether` has not been configured
yet, and none of them correspond to a successfully attached interface:

* **Branch 1** — `usbd_transfer_setup()` failure (if_kue.c:481-486). The
  `ue->ue_sc/ue_dev/ue_udev/ue_lock/ue_methods` assignments happen only at
  if_kue.c:495-499, i.e. *after* the failing call. `ue` is entirely zeroed
  (newbus softc is `M_ZERO`ed) except `sc_lock` (lockinit'd at if_kue.c:478).
* **Branch 2** — `kmalloc(...M_WAITOK) == NULL` (if_kue.c:488-493). Dead code
  on DragonFly (`M_WAITOK` cannot return NULL; with `sc_desc` still zeroed
  this is also a `kmalloc(0)` → ZERO_LENGTH_PTR, which is DF-2340's root),
  but it would equally run with a zeroed `ue`.
* **Branch 3** — `uether_ifattach()` error (if_kue.c:501-505), reachable only
  via `usb_proc_create()` ENOMEM (usb_ethernet.c:173-178). Here `ue` fields
  are set but the embedded ifnet was never `if_attach()`ed/`ether_ifattach()`ed
  and `ue_watchdog` was never callout-initialized (that happens in
  `ue_attach_post_task`, usb_ethernet.c:208, which never ran).

## Crash chain (branch 1, deterministic)

```
evil USB adapter (kue_devs[] VID:PID, config 0/iface 0, no bulk endpoints)
  → usbd_transfer_setup() = USB_ERR_NO_PIPE   (usb_transfer.c:1030-1053)
  → kue_attach() goto detach → kue_detach()   (if_kue.c:508-510)
  → uether_ifdetach(ue)                       (if_kue.c:520)
  → usb_proc_drain(&ue->ue_tq)                (usb_ethernet.c:273) — no-op on
      all-zero struct by design (usb_process.c:397-410)
  → ifp = uether_getifp(ue)                   (usb_ethernet.c:276) — embedded
      &ue->ue_arpcom.ac_if, NEVER NULL (usb_ethernet.c:133-137)
  → if (ifp != NULL)                          (usb_ethernet.c:278) — dead guard
  → UE_LOCK(ue) = lockmgr(NULL, LK_EXCLUSIVE) (usb_ethernet.c:61,281)
  → Fatal trap 12, fault VA 0x0
```

Branch 3 additionally runs `ether_ifdetach()` on a never-attached ifnet and
`devfs_clone_bitmap_put()` of a never-allocated unit — the same latent
ifindex/ifnet-list corruption documented for the siblings (DF-5334/5384/5395/
5397/5399/5411); it needs kthread-create exhaustion so it is the latent, not
the demonstrated, half.

## Reproduction

KLD harness `kue_attach_poc.c` (this pack) reconstructs the branch-1 state and
replays `kue_detach()`'s two production calls in order
(`usbd_transfer_unsetup()` + `uether_ifdetach()`, both from the stock
`uether.ko`). Baseline on the pristine `with-src` guest:

```
kue_poc: constructing post-'allocating USB transfers failed' state (if_kue.c:481-486)
kue_poc: state check: ue_lock=0 ue_dev=0 ue_udev=0 ue_tq.up_lock=0 (all must be 0/NULL)
kue_poc: entering kue_detach() replay: usbd_transfer_unsetup() + uether_ifdetach() (if_kue.c:519-520)
Fatal user address access from kernel mode from kldload at ffffffff80647bad
Fatal trap 12: page fault while in kernel mode
fault virtual address	= 0x0
current process		= 1040
Stopped at      lockmgr_exclusive+0x5d: orl     (%r14),%esi
```

(`panic.txt`; guest dead in DDB, `vm.sh status` ⇒ down.)

## Fix validation

`fix.diff`: (a) `uether_ifdetach()` early-returns when `ue->ue_lock == NULL`
(class-wide hardening, identical to the DF-5334/DF-5384 fix); (b) `kue_attach()`
routes all three failure `goto`s to a `detach_usb` label doing only
`usbd_transfer_unsetup()` + `kfree(sc->sc_mcfilters)` + `lockuninit(&sc->sc_lock)`.
Applied in-guest to `/usr/src` (patch(1) Plan A, both files), `uether.ko` and
`if_kue.ko` rebuilt `-Werror` clean (`fix_build.log`), patched `uether.ko`
installed into `/boot/kernel`, guest rebooted, **identical** harness re-run:

```
kue_poc: SURVIVED uether_ifdetach() (UNEXPECTED — guard present?)
KLDLOAD_RC=0      UNLOAD_OK      FATAL_COUNT=0
KUE_DRIVER_LOAD_OK / KUE_DRIVER_UNLOAD_OK
```

(`run.log`). Baseline panic vs patched survival on identical input. `fix.diff`
verified `git apply --check`-able against the clean read-only `sys/` tree.

## Why not higher severity

Fixed-address NULL deref at device-attach time; no attacker-controlled data
reaches memory corruption. Requires physical (or VM USB-passthrough) access
with a crafted adapter — same tier as the six siblings (Medium). Not a
user→root primitive.

## Pass-2 negative results (what else was hunted and killed)

* **rx path** (if_kue.c:531-578): frames shorter than 2+14 rejected
  (if_kue.c:547); device-supplied 16-bit length prefix clamped by
  `len = min(actlen, len)` (if_kue.c:555) with `actlen ≤ bufsize = MCLBYTES+2`
  (xfer length set to `usbd_xfer_max_len`, if_kue.c:561); `uether_rxbuf()`
  then rejects `len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN`
  (usb_ethernet.c:589) and copies at cluster offset `ETHER_ALIGN` — exact
  fit, no OOB (unlike urndis DF-5396, kue is fully protected by the core
  check). Oversize/undersize frames are silently dropped (return value of
  `uether_rxbuf` ignored — accounting nit only).
* **tx path** (if_kue.c:580-646): `m->m_pkthdr.len` clamped to MCLBYTES
  (if_kue.c:603-604) — only ever lowered, so `usbd_m_copy_in` stays in
  bounds; `temp_len ≤ MCLBYTES+2`, `total_len = temp_len + (64 - temp_len%64)
  ≤ MCLBYTES+66 → ≤ MCLBYTES+2+64 = bufsize` (if_kue.c:180,606,618); padding
  via `usbd_frame_zero` in-bounds. BPF after copy. Bounded.
* **mii/word helpers**: kue has no MII methods (if_kue.c:220-227);
  `kue_setword`/`kue_ctl` build fixed stack requests, `wLength` only from
  compile-time `sizeof`s (if_kue.c:247-279).
* **device-supplied data**: the 2-byte rx prefix (dead end, above);
  `sc_desc` feeds only `ue_eaddr` and `KUE_MCFILTCNT` — the latter is the
  known DF-1075/DF-2340 issue (not re-reported). Ignored `kue_ctl()` return
  in `kue_attach_post` (if_kue.c:439-443) yields an all-zero MAC on control
  transfer failure — robustness nit, no memory-safety impact.
* **lifetimes/locks**: rx/tx callbacks run under `sc->sc_xfer` lock =
  `sc->sc_lock`; `uether_ifdetach` drains the taskqueue before ifnet
  teardown; watchdog only armed when `ue_tick` set (kue sets none).

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