β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1152

BUG_ON kernel panic in atomic_check via MST connector without dc_sink

Summary

dm_update_crtcs_state at amdgpu_dm.c:5290 adds MST skip (goto next_crtc) when !dc_sink&&mst_port. At :5333 next_crtc label guard does NOT check stream!=NULL. At :5344 unconditional BUG_ON(dm_new_crtc_state->stream==NULL) fires because MST skip skipped stream assignment at :5305. Local user with /dev/dri/card0 issues DRM_IOCTL_MODE_ATOMIC with enable+active on CRTC bound to MST child with dc_sink==NULL (hot-unplugged downstream). Reliable kernel panic. Fix: add stream!=NULL to guard or remove BUG_ON.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1152 Β· 8 files
FileTypeDescriptionSize
VERDICT.md verdict Full source trace + reachability analysis 3.9 KB ↓ raw
fix.diff suggested-fix Strengthen guard at L5333 to also require stream!=NULL (git apply-able, validated) 509 B view raw
build.sh build-doc Documents why no executable PoC is possible 337 B view raw
run.sh run-doc Documents why runtime trigger is impossible on this guest 176 B view raw
env.txt environment uname + kernel symbol inventory proving amdgpu absent + no /dev/dri 395 B view raw
README.md readme human reproduce doc 749 B ↓ raw
../fix_build_combined.log build-log Combined 41-finding kernel build (rc=0, -Werror clean) 5.6 MB ↓ download
../fix_build_summary.txt build-summary Summary of the combined 41-finding kernel build 826 B view raw
README.md readme human reproduce doc
↓ download raw

DF-1152 β€” BUG_ON kernel panic in amdgpu_dm dm_update_crtcs_state

Result

NOT REPRODUCED on this guest. Real source-level defense-in-depth bug; fix authored. See VERDICT.md for the full analysis.

Build & run

./build.sh    # documents why no executable PoC is possible
./run.sh      # documents why runtime trigger is impossible

Reachability summary

  • amdgpu_dm is part of amdgpu, not in X86_64_GENERIC (0 symbols)
  • No AMD GPU on the QEMU guest, no /dev/dri
  • Trigger needs MST hot-unplug + DRM atomic ioctl on AMD hardware

Fix

fix.diff β€” strengthen guard at sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:5333 to also require dm_new_crtc_state->stream != NULL. Applies cleanly with git apply.

VERDICT.md verdict Full source trace + reachability analysis
↓ download raw

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:

/* 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:

/* 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.

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.

Fix verification

not_testable

git apply --check validated

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. amdgpu_dm BUG_ON on NULL stream via MST hot-unplug. amdgpu not in GENERIC.