# DF-5411 — if_udav.c attach-failure DF-5334-class panic (goto-detach-on-unattached)

## What

`udav_attach()` (`sys/bus/u4b/net/if_udav.c`) routes its device-controlled
failure branch through the full `udav_detach()` on a `usb_ether` that was
never attached — identical class to DF-5334 (if_cdce), DF-5384 (if_aue),
DF-5395 (if_axge), DF-5397 / DF-5399 (if_urndis / if_mos):

- `usbd_transfer_setup()` fails (missing bulk endpoints on an otherwise
  matching DM9601-class device) → if_udav.c:265-268 `goto detach` (:267) →
  if_udav.c:293-294 `udav_detach(dev)`.
- At that point `ue->ue_sc/ue_dev/ue_udev/ue_methods/ue_lock` are ALL still
  zero — they are assigned only at if_udav.c:280-283, *after* the failing
  call (the `lockinit(&sc->sc_lock)` at :260 initializes `sc_lock`, not
  `ue->ue_lock`).
- `udav_detach()` (if_udav.c:298-309) calls `uether_ifdetach(ue)`
  (if_udav.c:305) → `sys/bus/u4b/net/usb_ethernet.c:268-305`:
  `usb_proc_drain()` no-ops on the zeroed `ue_tq` (usb_process.c:401-412);
  `uether_getifp()` returns the embedded arpcom ifnet (usb_ethernet.c:134),
  never NULL — the `if (ifp != NULL)` guard is dead code; then
  `UE_LOCK(ue)` (usb_ethernet.c:281, macro at :58) =
  `lockmgr(NULL, LK_EXCLUSIVE)` → **Fatal trap 12, fault VA 0x0**.

The second failure branch (`uether_ifattach()` error, if_udav.c:285-288 —
reachable only on `usb_proc_create()` ENOMEM, not attacker-timed) leaves
`ue_lock` valid but a never-`if_attach()`ed ifnet, and reaches
`ether_ifdetach()` (usb_ethernet.c:294) → `if_detach()` on an unattached
ifnet → `ifindex2ifnet[0]` nulling + TAILQ_REMOVE of a never-inserted ifnet
from the global ifnet list — latent corruption pre-empted in branch 1 by the
NULL-write fault.

Threat model: attacker-supplied USB device (evil adapter / evil dock / VM
USB attach) presenting one of the 6 VID:PID pairs in `udav_devs[]`
(if_udav.c:205-218; e.g. ShanTou DM9601 `0x0fe6:0x8101`, Corega FEther
USB-TXC `0x07aa:0x0004`, Kontron JP1082) at config index 0 / iface 0
**without** the expected bulk-IN/OUT endpoints. Not remotely triggerable;
requires physical/VM USB access.

## Reproduce (evidence class: KLD harness driving production code)

QEMU has no DM9601 device model. The harness `udav_attach_poc.c` replays
`udav_detach()` **verbatim** (its production calls, in order) on the exact
state `udav_attach()`'s transfer-setup failure branch produces, using the
**production** `usbd_transfer_unsetup()` and `uether_ifdetach()` (exported
by `uether.ko`). The only non-production code is the static
`udav_attach`/`udav_detach` frame itself (static in if_udav.c, reachable
only via the `goto` with a physical device present).

```sh
# build (in guest, source pack at /root/df5411)
cd /root/df5411 && make -m /usr/src/share/mk

# BASELINE run (stock /boot/kernel/uether.ko auto-loaded by MODULE_DEPEND)
kldload -v ./udav_poc.ko
# expected: 3 marker lines, then
#   Fatal trap 12: page fault while in kernel mode
#   fault virtual address = 0x0
#   current process = ... (kldload)
#   Stopped at lockmgr_exclusive+0x5d: orl (%r14),%esi
# guest dead at db> — record: panic.txt

# PATCHED run (fix.diff applied to /usr/src, uether.ko rebuilt + installed)
kldload -v ./udav_poc.ko
# expected: 4th marker "udav_poc: SURVIVED uether_ifdetach()", RC=0,
#           0 Fatal traps, clean kldunload; patched if_udav.ko loads/unloads
# record: run.log
```

## Fix validation

`fix.diff` (git-apply-able against clean sys/):
(a) `uether_ifdetach()` early-returns when `ue->ue_lock == NULL`
(class-wide, same as the DF-5334/5384 validated fix);
(b) `udav_attach()` routes both pre-attach failures to a `detach_usb:`
label doing only `usbd_transfer_unsetup()` + `lockuninit()` — (b) is
required for the branch-2 `ether_ifdetach`-on-unattached corruption, which
(a) does not cover, and it also removes the now-dead `detach:` label.

Both `uether.ko` and `if_udav.ko` rebuilt `-Werror` clean in-guest; patched
`uether.ko` installed to `/boot/kernel`; identical harness run SURVIVED.

## Files

- `udav_attach_poc.c` + `Makefile` — the harness
- `build.log` — harness build (final, -Werror clean)
- `panic.txt` — baseline Fatal trap 12 record (serial console)
- `run.log` / `fix_run.log` — patched run: SURVIVED, RC=0, 0 traps
- `fix_uether_build.log`, `fix_udav_build.log`, `fix_build.log` — patched module builds
- `env.txt` — guest uname, cc, kldstat, patch confirmation
- `fix.diff` — the validated fix
- `VERDICT.md`, `manifest.json`, `verdict.json`
