⬢ DragonFlyBSD Kernel Audit
DF-3654 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3654",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Source-certain locking defect, hardware-gated runtime. handle_hpd_rx_irq() takes aconnector->hpd_lock iff dc_link->type != dc_connection_mst_branch on ENTRY (amdgpu_dm.c:1209-1210) but releases it iff the same condition holds on EXIT (1251-1254), re-reading the field after dc_link_detect() (1232) which can rewrite it in-handler: single->mst_branch at dc_link.c:528 (branch discovered from sink DPCD) and mst_branch->single at dc_link.c:569 (dm_helpers_dp_mst_start_top_mgr failure, sink-controlled sideband). Direction 1 strands hpd_lock permanently: later handle_hpd_irq() work items for the connector block forever (amdgpu_dm.c:1083), dm_suspend/dm_resume hang (864/878), amdgpu_dm_irq_fini flush_work() hangs (amdgpu_dm_irq.c:334) \u2014 persistent DoS. Direction 2 executes mutex_unlock() (= lockmgr LK_RELEASE) on a never-held lock (sys/dev/drm/include/linux/mutex.h:39) \u2014 lock corruption/panic. The pairing matrix was demonstrated on-guest by the harness (run.log); the kernel handler itself cannot run on the virtio-only guest (env.txt: no AMD GPU). likely rather than certain only because the in-handler type-flip hardware sequence (short-pulse HPD-RX that runs detection discovering/losing the branch) is device-timing-dependent \u2014 the DF-3626 sink-controlled-condition class.",
  "exploit_chain": "Malicious/defective DisplayPort dock or sink (physical or supply-chain): presents MST branch caps so an HPD-RX short pulse causes dc_link_detect() inside handle_hpd_rx_irq() to flip link->type single->mst_branch while hpd_lock is held -> lock stranded -> all later HPD processing for the connector, suspend/resume, and driver teardown hang permanently. Alternate direction: make topology start fail after the link is classified MST to trigger unlock-without-hold -> lockmgr state corruption/panic.",
  "evidence": "run.log (pairing matrix: STRANDED LOCK and UNLOCK WITHOUT HOLD cells with dc_link.c:528/569 annotations); VERDICT.md (full source trace incl. lock shim mapping); fix.diff (cached lock decision; git apply --check clean); env.txt (guest virtio-only)",
  "kernel_refs": [
    "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1209",
    "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1232",
    "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1251",
    "sys/dev/drm/amd/display/dc/core/dc_link.c:528",
    "sys/dev/drm/amd/display/dc/core/dc_link.c:569",
    "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1083",
    "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c:334"
  ],
  "poc_changes": "no seeded PoC for pass-2; harness written fresh \u2014 enumerates the entry x exit decision matrix exactly as the kernel computes the two conditionals",
  "attempts": 1,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "runtime_sec": 55,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -o harness harness.c",
  "run_cmd": "./harness",
  "code_hash": "9fa3a99168441f5c0028d09c5bc6b1108d7b41557175e81ff4ea851db1eb7562",
  "notes": "pass 2 amdgpu_dm.c; sink-driven surface per briefing item (2); guest scratch removed",
  "recommended_fix": "Cache the lock decision at handler entry (bool hpd_lock_taken = dc_link->type != dc_connection_mst_branch) and gate lock and unlock on the cached value.",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Hardware-gated: requires an amdgpu-backed DP connector and a sink that flips the link classification inside one HPD-RX handling. fix.diff makes lock/unlock symmetric on a cached decision; git apply --check verified against sys/; not applied (read-only audit target).",
  "fix_evidence": "fix.diff in this pack"
}