# DF-4589 VERDICT — not_reproduced (hardware-gated), defect certain from source

## Finding

`radeon_dp_link_train_cr()` (sys/dev/drm/radeon/atombios_dp.c:668-733) has no
overall iteration bound.  Its four exit conditions:

1. `drm_dp_dpcd_read_link_status(...) <= 0` — atombios_dp.c:687-691 (sink/HW failure only)
2. `drm_dp_clock_recovery_ok(...)` — :693-696 (sink achieves CR)
3. all lanes `DP_TRAIN_MAX_SWING_REACHED` — :698-705 (requires voltage level 3)
4. 5 **consecutive** equal-voltage iterations — :707-714, with
   `else dp_info->tries = 0;` at :713-714 resetting the counter on ANY change

are all sink-controlled.  A crafted sink alternating its adjust-request
voltage between levels < 3 while never reporting CR keeps `tries` at 0
indefinitely → infinite loop with per-iteration delay
(drm_dp_link_train_clock_recovery_delay, sys/dev/drm/drm_dp_helper.c:121-134:
`udelay(100)` minimum, `mdelay(rd_interval*4)` up to ~508 ms via DPCD[0x0E])
plus a DPCD read.

## Why it is exploitable / who spins

Call chain: userspace modeset / hotplug → encoder DPMS-on
(atombios_encoders.c:1777 `radeon_dp_link_train(encoder, connector)`) inside
the DRM modeset path holding `dev->mode_config.mutex`.  Consequences:

* the issuing thread (user ioctl or HPD workqueue) spins forever,
  non-interruptibly — unkillable process;
* `mode_config.mutex` is held forever — every subsequent DRM ioctl on the
  card blocks: permanent display-subsystem DoS for all users of the GPU.

Distinct from DF-1778 (unbounded goto-loop in radeon_dp_mst.c check_status)
and DF-1730 (lane-count OOB): different file, different loop, different
primitive (pure DoS, no memory access violation).

## Reproduction attempt on the audit guest

* Guest: DragonFly 6.5-DEVELOPMENT X86_64_GENERIC (env.txt).
* run.sh / run.log: no AMD GPU (vendor 0x1002) — only Bochs 0x1234:0x1111.
  A crafted DP sink additionally requires physical DP attachment.
* Therefore the runtime trigger cannot execute on this guest: **status
  not_reproduced, reproduced=0, impact none (not manifested here)**.
  Realistic impact ceiling on real hardware: kernel-thread wedge /
  unkillable process + display DoS (physical, no privilege gain).

Confidence in the code defect: certain — every exit condition is enumerated
above and each is under sink control; the counter-reset at :713-714 is
unconditional on voltage change.  Exploitation likelihood: likely (needs a
crafted sink; trivially implementable on an MCU DP dongle, as with prior
malicious-sink research).

## Fix validation

fix.diff adds a hard cap of 50 CR iterations (covers worst-case legitimate
voltage walks: 4 levels x 5 tries with resets) and logs "clock recovery
exceeded max loop attempts".  Baseline vs patched cannot be exercised on
this guest (no radeon HW) → fix_status: not_testable; the diff is
line-accurate against atombios_dp.c:668-722.

## Artifacts

* trigger.c — deterministic malicious-sink state machine + loop trace table
* run.sh, run.log, guest_probe.log, env.txt — guest hardware-absence proof
* fix.diff — iteration cap
* manifest.json / verdict.json

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
