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

dce120 TG: CRTC_REG_UPDATE_4/_5 pass pair-count 3 - 4th/5th CRTC register-field updates silently dropped (CRTC_TEST_PATTERN_COLOR_FORMAT / VRES / RAMP0_OFFSET never programmed)

Summary

CRTC_REG_UPDATE_4/_5 expand to CRTC_REG_UPDATE_N(reg, 3, ...) - the count literal is 3 for both, and generic_reg_update_ex consumes exactly n triples, so the 4th/5th field updates are silently dropped: COLOR_FORMAT never programmed for COLORSQUARES/V-H-BARS; VRES and RAMP0_OFFSET never programmed for COLORRAMP (10bpc loses RAMP0_OFFSET=384<<6). Reading fewer varargs than passed is defined behavior - no over-read; sinks are masked MMIO RMWs. Upstream-inherited verbatim (Linux 4.15 and master both carry n=3). Correct-the-count-literals fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4435 Β· 5 files
FileTypeDescriptionSize
README.md β€” 2.4 KB ↓ raw
VERDICT.md β€” 2.8 KB ↓ raw
verdict.json β€” 2.8 KB view raw
manifest.json β€” 1.1 KB view raw
fix.diff β€” 1.1 KB view raw

DF-4435 β€” dce120 timing generator: CRTC_REG_UPDATE_4/_5 pass pair-count 3

Severity / class

Info (correctness defect in a diagnostic hardware path; no memory-safety impact). Upstream-inherited: present verbatim in Linux v4.15 and, as of 2026-09, still in upstream master drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c.

What is wrong

sys/dev/drm/amd/display/dc/dce120/dce120_timing_generator.c:57-61:

#define CRTC_REG_UPDATE_4(reg, f1,v1, f2,v2, f3,v3, f4,v4) \
        CRTC_REG_UPDATE_N(reg, 3, FD(...f1), v1, FD(...f2), v2, FD(...f3), v3, FD(...f4), v4)
#define CRTC_REG_UPDATE_5(reg, f1,v1, f2,v2, f3,v3, f4,v4, f5,v5) \
        CRTC_REG_UPDATE_N(reg, 3, FD(...f1), v1, ..., FD(...f5), v5)

Both pass n = 3 (the _3 variant's count) while supplying 4 and 5 (shift, mask, value) triples. generic_reg_update_ex (sys/dev/drm/amd/display/dc/dc_helper.c:32-58) consumes exactly n triples (while (i < n) va_arg(...)), so the 4th and 5th field updates are silently dropped β€” reading fewer varargs than passed is defined and safe, so this never corrupts memory; it just fails to program the fields.

Consequence (register fields never written)

  • dce120_timing_generator.c:921-925 and :1023-1027 (CRTC0_CRTC_TEST_PATTERN_CONTROL, 4-field update): CRTC_TEST_PATTERN_COLOR_FORMAT is never programmed for the COLORSQUARES / VERTICALBARS / HORIZONTALBARS test patterns.
  • dce120_timing_generator.c:1062-1087 (CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 5-field update): CRTC_TEST_PATTERN_VRES and CRTC_TEST_PATTERN_RAMP0_OFFSET are never programmed for the COLORRAMP patterns (the 10bpc case intends RAMP0_OFFSET = 384 << 6).

All sinks are field-masked MMIO read-modify-writes to constant CRTC registers; no kernel-memory write primitive, no OOB. Worst case the DP test pattern renders with a stale color format / ramp geometry on a Vega10-class ASIC (DRM_MASTER-triggered via debugfs or a DP automated test request from a sink).

Why not guest-tested

Requires DCE12 (Vega10) display hardware. The audit QEMU guest has no DRM device at all (/dev/dri absent; only an unbound std-VGA chip), so the code path cannot execute there. Static proof only (this is an Info finding; QEMU verification not warranted per audit contract).

Fix

fix.diff β€” pass 4 and 5 respectively (matches the macro names and the manual _N call sites elsewhere in the same file, e.g. the 6-pair DCP0_DCP_GSL_CONTROL update at :273 passes 6).

VERDICT.md
↓ download raw

DF-4435 VERDICT β€” static, upstream-inherited macro-count defect

Reproduced?

No runtime verification performed (status: untested). Justification: requires DCE12/Vega10 display hardware; the audit QEMU guest has no DRM device (/dev/dri absent β€” see the DF-4437 pack's env.txt). This is an Info-severity finding; the audit contract mandates QEMU verification only for Critical/High or hammer2/memcorrupt/privesc findings.

Why the defect is certain anyway (line-by-line proof)

  1. sys/dev/drm/amd/display/dc/dce120/dce120_timing_generator.c:57-58: CRTC_REG_UPDATE_4(reg, f1,v1..f4,v4) expands to CRTC_REG_UPDATE_N(reg, 3, <4 triples>) β€” the count literal is 3. Same at :60-61 for _5 with 3.
  2. sys/dev/drm/amd/display/dc/dm_services.h:169-172: generic_reg_update_soc15(..., n, ...) forwards n as the varargs triple count.
  3. sys/dev/drm/amd/display/dc/dc_helper.c:32-58: generic_reg_update_ex applies the first triple via named parameters and then while (i < n) consumes exactly n-1 further triples via va_arg. With n=3 and 4/5 triples supplied, the surplus triples are simply never read β€” defined behavior, no over-read, fields dropped.
  4. Call sites that lose fields (all in the same file): - :917-925 CRTC0_CRTC_TEST_PATTERN_CONTROL 4-field update β€” CRTC_TEST_PATTERN_COLOR_FORMAT dropped (COLORSQUARES). - :1023-1027 same register β€” CRTC_TEST_PATTERN_COLOR_FORMAT dropped (VERT/HORIZONTAL BARS). - :1062-1087 CRTC0_CRTC_TEST_PATTERN_PARAMETERS 5-field updates β€” CRTC_TEST_PATTERN_VRES and CRTC_TEST_PATTERN_RAMP0_OFFSET dropped (COLORRAMP; the 10bpc case loses 384<<6).
  5. Upstream parity: Linux v4.15 and current master both carry the same n=3 literals (verified against raw.githubusercontent.com, v4.15 and master, 2026-09-20) β€” never fixed upstream; DF inherited it verbatim.

Security impact ceiling

All sinks are masked MMIO read-modify-writes to fixed CRTC registers (set_reg_field_value_ex masks by field). No kernel memory write, no OOB, no leak. Worst case: DP test patterns (DRM_MASTER / debugfs / DP automated-test-request triggered) render with a stale COLOR_FORMAT / ramp geometry on Vega10-class hardware. Filed as Info.

Fix validation

Not applicable (no runtime repro possible on available hardware). fix.diff corrects the two count literals β€” mechanically identical to the correct _2/_3 macros beside them and to the explicit 6-pair CRTC_REG_UPDATE_N(DCP0_DCP_GSL_CONTROL, 6, ...) at :273.

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_testable
baseline no→ patch + rebuild →patched clean

No behavior validation possible (no DCE12 hardware, guest has no DRM device); fix.diff is a 2-literal correction that makes the macros consistent with the _2/_3 siblings and the explicit 6-pair call at dce120:273; verified to apply cleanly with patch --dry-run

findings/poc/DF-4435/fix.diff (patch -p1 --dry-run: OK)
↓ fix.diffper-fix-DF-4435

Confirmed kernel references

Detail

Evidence (decisive lines)

findings/poc/DF-4435/VERDICT.md (line-by-line macro/varargs proof + upstream parity URLs); fix.diff (applies cleanly, patch --dry-run verified)

PoC changes

No PoC authored: code path needs DCE12 ASIC hardware; guest lacks any DRM device

Verified recommended fix

Correct CRTC_REG_UPDATE_4/_5 to pass 4 and 5 respectively to CRTC_REG_UPDATE_N

Verdict

Certain static defect, no runtime security impact demonstrable on available hardware. CRTC_REG_UPDATE_4/_5 in dce120_timing_generator.c:57-61 pass pair-count 3 to CRTC_REG_UPDATE_N; generic_reg_update_ex (dc_helper.c:32-58) consumes exactly n (shift,mask,value) triples, so the 4th/5th field updates are silently dropped: CRTC_TEST_PATTERN_COLOR_FORMAT is never programmed (dce120:921-925,1023-1027) and CRTC_TEST_PATTERN_VRES/RAMP0_OFFSET never programmed (dce120:1062-1087). Reading fewer varargs than supplied is defined behavior - no memory-safety primitive; all sinks are masked MMIO RMWs to constant CRTC registers. Upstream-inherited verbatim (Linux v4.15 and current master both carry n=3). Untested because it requires Vega10/DCE12 display hardware; the audit QEMU guest has no DRM device at all (/dev/dri absent). Info severity - QEMU verification not mandated.