DF-4910 / verdict.json
{ "finding_id": "DF-4910", "status": "untested", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "Code-proven race: dm_dp_destroy_mst_connector (amdgpu_dm_mst_types.c:386-392) tears down aconnector->port/dc_sink from drm_dp_destroy_connector_work with no mode_config.mutex (drm_dp_mst_topology.c:3103-3116 deliberately lockless), while dm_dp_mst_get_modes (amdgpu_dm_mst_types.c:232-244) check-then-sets the same dc_sink under mode_config.mutex from the unpriv DRM_IOCTL_MODE_GETCONNECTOR path (drm_connector.c:1759-1763). The losing interleaving leaks the dc_sink into link->remote_sinks[] with dc_sink->priv dangling at the kfreed aconnector, permanently consumes one of MAX_SINKS_PER_LINK(4) slots, and after 4 hits makes the known DF-1966 NULL-deref panic deterministic; secondary UAF-read windows exist in amdgpu_dm_update_freesync_caps (amdgpu_dm.c:5855) and amdgpu_dm_connector_mode_valid (amdgpu_dm.c:3324-3331). NOT runtime-tested: the audit guest has no AMD display device (only the QEMU virtual VGA), amdgpu.ko loads but binds nothing, /dev/dri does not exist \u2014 recorded in run.log/env.txt. Fix (mode_config.mutex around the teardown) authored in fix.diff but not buildable-into a testable configuration on this guest because the buggy path requires AMD DM hardware with a DP MST topology.", "exploit_chain": "unpriv GETCONNECTOR hammer x MST topology flap (physical replug / hostile DP dongle) -> unlocked destroy skips dc_sink release while probe installs it -> dc_sink leaked with ->priv dangling at freed aconnector; after 4 races every later dc_link_add_remote_sink fails (dc.c:1752) -> next hotplug NULL-deref panic in dm_dp_mst_get_modes (DF-1966 amplifier); UAF-read windows at amdgpu_dm.c:5855/3324 are read-only primitives, no write primitive identified.", "evidence": "VERDICT.md (full line-by-line trace + killed candidates), run.log (guest: NO_AMD_PCI_DEVICE / NO_DEV_DRI, trigger builds and runs, path unreachable), env.txt (uname 6.5-DEVELOPMENT, amdgpu.ko present but unbound), fix.diff (mode_config.mutex serialization).", "kernel_refs": [ "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c:232", "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c:243", "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c:244", "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c:386", "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c:387", "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c:389", "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c:390", "sys/dev/drm/drm_dp_mst_topology.c:3093", "sys/dev/drm/drm_dp_mst_topology.c:3116", "sys/dev/drm/drm_probe_helper.c:400", "sys/dev/drm/drm_connector.c:1759", "sys/dev/drm/amd/display/dc/core/dc.c:1752", "sys/dev/drm/amd/display/dc/core/dc.c:1757", "sys/dev/drm/amd/display/dc/core/dc.c:1834", "sys/dev/drm/amd/display/dc/dc.h:45", "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:3324", "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:5845", "sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c:5855" ], "poc_changes": "No seeded PoC existed; wrote mst_race_trigger.c from scratch (DRM ioctl constants embedded since guest lacks installed drm headers).", "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": 240, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o mst_race_trigger mst_race_trigger.c", "run_cmd": "./run.sh (build + pciconf probe + ./mst_race_trigger /dev/dri/card0)", "code_hash": "e1e328bc79557afa2716b4288d052327b0e0e5574e04616e38504070d56f65d5", "notes": "Guest was probed with kldload amdgpu (loads, binds nothing \u2014 only QEMU virtual VGA chip 0x1234 present); the follow-up kldunload wedged the linker lock so the guest was reset with-src and is clean. amdgpu.ko exists at /boot/kernel/amdgpu.ko. Distinct root cause from known DF-4748 (helpers read stale priv of a stream-owned sink) and DF-1966 (unchecked add_remote_sink NULL) \u2014 this finding is the unlocked teardown racing the probe, creating the leak/dangling window in the first place.", "recommended_fix": "Hold dev->mode_config.mutex across the aconnector->port/dc_sink teardown in dm_dp_destroy_mst_connector (see fix.diff).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "Fix cannot be validated on this guest: baseline cannot run (no AMD display hardware, no /dev/dri). fix.diff is a minimal, deadlock-audited serialization patch (the cbs only caller invokes it lockless).", "fix_evidence": "fix.diff; call-site proof drm_dp_mst_topology.c:3103-3116 holds no locks when calling cbs->destroy_connector." } |