# DF-5306 — NULL-deref kernel panic at attach when the VideoControl header lists zero VideoStreaming interfaces

## Where

`sys/bus/u4b/uvc/uvc_drv.c:2106-2146` (`uvc_drv_parse_standard_ctrl()`,
case `UDESCSUB_VC_HEADER`) — with `bIfaceNums == 0` (or `bLength < 12`,
or no VC header descriptor at all) `vsnum` becomes/stays 0, the
`sc->data = uvc_drv_init_data(...)` loop never runs, and
`uvc_drv_parse_ctrl()` still returns 0 (success).  `uvc_drv_attach()`
(uvc_drv.c:2723-2731) then calls
`uvc_drv_init_video(sc, sc->ctrl, sc->data /* == NULL */)`, which
dereferences `data->num_altsetting` at `uvc_drv.c:1513`:

```c
	if (data->num_altsetting > 1)     /* data == NULL -> read at 0xA */
```

## Attack model

Crafted USB webcam descriptors (evil-USB device; QEMU-emulatable): a
UVC control interface whose header declares no streaming interfaces.
Kernel panics during device attach — local DoS.

## Build / run (as verified)

    ./build.sh
    ./run.sh          # kldload, then: sysctl hw.uvcharness=2

The harness runs the real `uvc_drv_parse_ctrl()` on a blob with
`bIfaceNums=0`, prints the resulting `sc.data == NULL`, then calls the
real `uvc_drv_init_video(sc, ctrl, NULL)`.

## Expected (baseline)

    HARNESS DF-5306: parse_ctrl ret=0 sc.data=0 (expected NULL)
    HARNESS DF-5306: calling real uvc_drv_init_video(sc, ctrl, NULL) ...
    Fatal trap 12: page fault while in kernel mode
    fault virtual address = 0xa
    Stopped at sysctl_harness+0x30b: cmpb $0x1,0xa(%r9)
    -> guest dead (db> prompt)

`0xa` is exactly the offset of `num_altsetting` in
`struct uvc_drv_data` (uvc_drv.h:645-651).

## After fix.diff

    HARNESS DF-5306: parse_ctrl ret=22 sc.data=0      (EINVAL at parse)
    HARNESS DF-5306: returned 0 (UNEXPECTED - no panic)
    -> guest stays up

## Files

    panic.txt   verbatim serial console of the crashed run
    run.log     baseline console output
    fix.log     post-fix output (no panic, guest alive)
    fix.diff    git-apply-able unified diff (git apply -p0)
