Output-lock asymmetry: radeon_legacy_tmds_int_commit and radeon_legacy_tv_dac_commit re-LOCK the output instead of unlocking after modeset
Summary
prepare() locks the output; commit() must release. All three sibling commit functions pass false, but tmds_int_commit and tv_dac_commit pass true - copy-paste of the prepare side. The output PLL lock stays asserted after every DVI/TV modeset, inhibiting subsequent DPMS/modeset register programming by the BIOS command processor (upstream passes false in both). Functional display DoS on r100-r500; register-bit only. Four-token flip fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4226 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.6 KB | β raw | |
| VERDICT.md | β | 2.0 KB | β raw | |
| fix.diff | β | 924 B | view raw | |
| verdict.json | β | 2.2 KB | view raw |
DF-4226 β radeon legacy commit paths re-LOCK the output instead of unlocking
What (pure source-level finding, hardware-gated)
The prepare/commit protocol of the DRM encoder helpers is:
prepare() locks the output PLL against BIOS command-processor updates
(radeon_atom_output_lock(encoder, true)), commit() must release it
(..., false).
In sys/dev/drm/radeon/radeon_legacy_encoders.c two commit functions pass
true (lock) again:
radeon_legacy_tmds_int_commit()β drm lines 775, 777radeon_legacy_tv_dac_commit()β drm lines 1146, 1148
Every sibling in the same file does it correctly:
- radeon_legacy_lvds_commit() β lines 169/171 (false)
- radeon_legacy_primary_dac_commit() β lines 578/580 (false)
- radeon_legacy_tmds_ext_commit() β lines 940/942 (false)
Consequence: after any modeset on the internal-TMDS (DVI) or TV-DAC encoder,
the output remains locked; subsequent DPMS/modeset PLL programming via the
BIOS command tables is inhibited β persistent display malfunction (blank
output / failed modesets) until re-init. This is a functional DoS of the
display pipeline; no memory-safety impact (register bit only).
Upstream Linux fixed both call sites to false.
Reproduce
Not reproducible on the QEMU guest: requires r100βr500 radeon hardware
(guest has Bochas VGA, no DRM device). Source-level certainty: the asymmetry
is self-evident against the three correct siblings in the same file, and
prepare() at lines 762/764 (tmds_int) and 1133/1135 (tv_dac) locks with
true β commit() must mirror with false.
Fix
true β false at the four cited lines (see fix.diff).
DF-4226 β VERDICT
Status: untested β hardware-gated (requires ATI r100βr500 GPU; the QEMU
guest has Bochs VGA 0x1234:1111, no /dev/dri, and radeon.ko cannot
attach). Source-level certainty is complete; no runtime behavior needs to
be observed to establish the defect.
Why this is certain from source alone
- The helper contract is symmetric:
prepare()callsradeon_{atom,combios}_output_lock(encoder, true)to lock the output during reprogramming (radeon_legacy_encoders.c:762/764 for tmds_int, 1133/1135 for tv_dac);commit()must call the same function withfalseto release the lock. Three of five legacy encoders in this very file do exactly that (lvds: 168-171, primary_dac: 577-580, tmds_ext: 939-942). radeon_legacy_tmds_int_commit()(768-778) andradeon_legacy_tv_dac_commit()(1139-1149) instead call the lock function withtrueβ a copy-paste of the prepare() side. The output PLL lock bit stays asserted after the modeset completes.- Upstream Linux drivers/gpu/drm/radeon/radeon_legacy_encoders.c passes
falsein both commit functions; the DragonFly tree diverges.
Impact
Functional display DoS on affected hardware after a DVI/TV modeset (output stays locked; later DPMS/modeset register updates via the BIOS command processor fail). Triggering requires DRM master (modeset). No memory corruption, no info leak β register-bit-only defect, hence Low.
Fix
fix.diff flips the four true arguments to false (lines 775, 777, 1146,
1148). Fix boot validation is not testable on this guest (no radeon GPU);
the change restores exact parity with the three correct sibling functions.
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.
Fix verification
not_testableNo radeon hardware on the guest; fix is a four-argument change restoring exact parity with the three correct sibling commit functions in the same file.
fix.diff; source comparison in VERDICT.md
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md side-by-side of the five prepare/commit pairs in the file; fix.diff flips the four arguments to false, restoring parity with siblings and upstream Linux.
PoC changes
n/a (source-level finding)
Verified recommended fix
Pass false to radeon_{atom,combios}_output_lock in radeon_legacy_tmds_int_commit and radeon_legacy_tv_dac_commit (lines 775/777/1146/1148).
Verdict
Hardware-gated functional defect (no memory-safety impact, hence impact=none): radeon_legacy_tmds_int_commit (radeon_legacy_encoders.c:775/777) and radeon_legacy_tv_dac_commit (:1146/1148) call radeon_{atom,combios}_output_lock with true (LOCK) where the prepare/commit contract and all three sibling commit functions in the same file (lvds:169, primary_dac:578, tmds_ext:940) pass false (UNLOCK). After a DVI/TV modeset the output stays locked and later DPMS/modeset register programming is inhibited β display DoS until re-init, triggerable by a DRM master. Requires r100-r500 hardware; the QEMU guest has Bochs VGA and no DRM device, so no runtime test is possible or needed: the asymmetry is fully established from source.
No comments yet.