# DF-1152 — `BUG_ON` kernel panic in `dm_update_crtcs_state` via MST connector

## Verdict
**NOT REPRODUCED** on this guest (defense-in-depth source bug confirmed; path
unreachable on the default GENERIC DragonFlyBSD kernel running in QEMU).
Real source-level defect; fix.diff authored.

## Mechanism (source trace, bug confirmed real)
In `sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c`, `dm_update_crtcs_state()`
runs the CRTC update logic in two passes — first with `enable=false`
(disables), then with `enable=true` (enables), called from
`amdgpu_dm_atomic_check()` (`:5688` and `:5694`).

When called with `enable=true`, the per-CRTC body has this flow:

```c
/* sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:5284-5291 */
} else { /* Add stream for any updated/enabled CRTC */
    ...
    /* L5290 */ if (!aconnector || (!aconnector->dc_sink && aconnector->mst_port))
    /* L5291 */     goto next_crtc;
    ...
    /* L5305 */ dm_new_crtc_state->stream = new_stream;   /* ONLY inside modeset_required */
```

The MST "quick fix" at L5290 jumps past the only stream assignment at L5305.
Then at the `next_crtc:` label:

```c
/* sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:5324-5344 */
next_crtc:
    /* L5326 */ if (new_stream) dc_stream_release(new_stream);
    ...
    /* L5333 */ if (!(enable && aconnector && new_crtc_state->enable &&
    /* L5334 */       new_crtc_state->active))
    /* L5335 */     continue;
    ...
    /* L5344 */ BUG_ON(dm_new_crtc_state->stream == NULL);   /* UNCONDITIONAL */
```

The guard at L5333 checks `enable && aconnector && crtc_enable && active`
but **does NOT** check `dm_new_crtc_state->stream != NULL`.  So the path:

1. Unprivileged local user opens `/dev/dri/card0` (amdgpu render node),
2. Issues `DRM_IOCTL_MODE_ATOMIC` requesting enable+active on a CRTC that is
   bound to a now-hot-unplugged MST downstream port (so `aconnector` is
   non-NULL but `dc_sink == NULL` and `mst_port == true`),
3. `dm_update_crtcs_state(enable=true)` skips stream assignment at L5290
   (MST goto), but the L5333 guard passes (enable/active/connector all OK),
4. **L5344 `BUG_ON(stream == NULL)` fires → kernel panic**.

This is a real logic bug — the guard at L5333 must also require
`dm_new_crtc_state->stream != NULL`, or the BUG_ON must be replaced with
`continue`/graceful failure.  (The kernel's `BUG_ON` expands to `panic()`
on DragonFly/linuxdrm.)

## Why it does NOT reproduce on this guest
1. **amdgpu_dm is part of the amdgpu driver which is not in GENERIC.**
   `grep -E 'radeon|amdgpu' sys/config/X86_64_GENERIC` is empty;
   `nm /boot/kernel/kernel.debug | grep -ciE 'radeon|amdgpu'` ⇒ **0**.
   The amdgpu.ko loadable module exists but is **not loaded** on this guest
   (`kldstat | grep amdgpu` empty).
2. **No AMD GPU in the QEMU guest.** Even with the module loaded there is
   no Display Core (DC) on the virtual PCI bus, so `aconnector`/`dc_sink`
   never exist and the DRM atomic ioctl has no amdgpu CRTC to act on.
3. **Threat model is local user with GPU + MST hub.** The trigger requires
   AMD hardware with DisplayCore (e.g. Raven Ridge / Navi / newer APU or
   dGPU), a daisy-chained MST hub, a hot-unplug event on the downstream
   port, and then the atomic modeset request — none of which exist in this
   serial-console QEMU VM.

## Exploit chain
none — primitive (kernel panic via BUG_ON) requires AMD GPU + MST topology
+ module load + DRM atomic ioctl, none of which are present on this guest.

## PoC changes
none — no executable PoC is possible; the path is dead code in the running
kernel and requires AMD hardware that the QEMU VM does not have.

## Recommended fix
Replace the unconditional `BUG_ON(...)` at L5344 with a graceful `continue`
when `stream == NULL`, AND/OR strengthen the guard at L5333 to also require
`dm_new_crtc_state->stream != NULL`.  See `fix.diff` — applies cleanly
with `git apply` (validated).  Matches the finding markdown's proposal.
