dce110_timing_generator_validate_timing: h_blank/h_back_porch u32 underflow bypasses the minimum checks; no vertical checks -> program_blanking programs wrapped (masked) blanking registers
Summary
validate_timing computes h_blank and h_back_porch with u32 subtractions that wrap on inconsistent timings: h_total < h_addressable+borders makes h_blank ~4G (passes the min check), h_sync_width > h_front_porch makes h_back_porch wrap (passes its check). No vertical checks at all. The accepted timing is later programmed by program_blanking whose identical math wraps and is masked into the H/V BLANK registers. All sinks are masked MMIO to constant addresses - not kernel memory corruption; impact ceiling is an inconsistent CRTC timing on real ASIC (display corruption; speculative pipe hang). drm helpers normally pre-validate userspace modes; this is the defense-in-depth layer being bypassed. Reject-underflow fix (compile-validated with -Werror amdgpu.ko build).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4091 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.2 KB | β raw | |
| VERDICT.md | β | 2.9 KB | β raw | |
| env.txt | β | 1.4 KB | view raw | |
| fix.diff | β | 1.1 KB | view raw | |
| fix_build.log | β | 1.2 MB | β download | |
| manifest.json | β | 709 B | view raw | |
| verdict.json | β | 2.8 KB | view raw |
DF-4091 β dce110_timing_generator_validate_timing underflow lets inconsistent timings pass; program_blanking programs wrapped blanking values
File: sys/dev/drm/amd/display/dc/dce110/dce110_timing_generator.c
(validate :1109-1163; sink program_blanking:596-697)
Class: CWE-191 integer underflow in the display timing gatekeeper
(checklist item (d): bounds rejects)
Severity: Low β pass 2 (GLM 5.3), bucket base:dev
Confidence: certain (arithmetic); hardware-gated impact
The bug
dce110_timing_generator_validate_timing() is the CRTC-level gatekeeper β
called for every stream via dc_validate_stream()
(core/dc_resource.c:2873). Two of its computations wrap on u32:
h_blank = h_total - h_addressable - h_border_right - h_border_left; /* :1144 */
if (h_blank < tg110->min_h_blank) return false; /* passes if wrapped */
...
h_back_porch = h_blank - (h_front_porch - h_sync_width); /* :1154-1157, wraps */
- If
h_total < h_addressable + borders,h_blankunderflows to ~4 G and sails through the< 56check. - If
h_sync_width > h_front_porch,h_back_porchunderflows and passes< 4. - There are no vertical checks at all (no
v_addressablefit, no v-porch minimums).
The accepted timing is later programmed by
dce110_timing_generator_program_blanking() / program_timing_generator():
tmp = timing->h_total - (h_sync_start + timing->h_border_left); /* :656-657 */
...
tmp = timing->v_total - (v_sync_start + timing->v_border_top); /* :679 */
both of which wrap the same way; set_reg_field_value_ex()
(dm_services.h:133-141) masks the wrapped value into the field, so the
CRTC receives garbage (truncated-to-13/16-bit) H/V blank start/end values.
Impact ceiling (honest)
- Not kernel memory corruption: every value is field-masked into fixed
MMIO registers computed from constant register offsets
(
CRTC_REG/DCP_REG); no pointer or length is derived from timing data anywhere in this file (no division exists either β the DF-3828 watermark div0 class is absent here). - Worst realistic effect: an inconsistent CRTC timing (blanking window that does not exist inside the total) is programmed β display corruption, loss of sync, or a wedged display pipe; a hang would be a system-level DoS (speculative β no ASIC available to test).
- Userspace normally cannot smuggle such a mode past DRM-core mode
validation (
hdisplay β€ htotaletc.), butdc_validate_streamexists as defense-in-depth and is bypassable by any internal producer that adjusts timings (e.g. DRR/FreeSync v_total adjustments inset_drr:366-468, which itself only masks values).
Hardware-gated: the audit guest has no AMD ASIC (env.txt), so no runtime
verification was possible; source-level certainty only, matching the dce110
family checklist instruction.
Fix
fix.diff β reject timings whose active+borders do not fit inside the
totals (h and v), reject zero addressable, and guard the back-porch
computation against its underflow before it happens. Compile-validated: the
whole amdgpu.ko module (which compiles this file) rebuilt with -Werror
after applying the diff (BUILD_EXIT=0, fix_build.log).
DF-4091 VERDICT
Status: untested β hardware-gated (no AMD ASIC on the audit guest;
vgapci0 ... chip=0x11111234 is QEMU std VGA, env.txt). Source-level
certainty, per the dce110-family checklist instruction.
Confidence: certain (arithmetic defects); impact ceiling speculative
(no hardware to observe a misprogrammed CRTC).
What was checked (whole file, 2261 lines)
- (a) program_timing / program_blanking arithmetic (
:281-353,:596-697): all h/v sync-start and blank-start/end computations can wrap (u32) on inconsistent timings, but every sink isset_reg_field_value_ex(dm_services.h:133-141) which masks to the register field width beforedm_write_regto a constant address (CRTC_REG/DCP_REG+ fixed offsets). No kernel-memory effect is reachable from timing values. No division exists in the file (DF-3828 watermark-div0 class absent). - (b) set_drr / vtotal bounds (
:366-468):vertical_total_max/minzero-checked (:387-389);-1values masked into fields. Benign. - (c) test pattern generators (
:699-1102): fixed arrayssrc_color[6]/dst_color[6], loops bounded by 6; shiftssrc_bpc - dst_bpcβ {6,8,10},16 - dst_bpcβ {6,8,10}; no UB. - (d) validate_timing (
:1109-1163): the finding βh_blank(:1144-1146) andh_back_porch(:1154-1157) underflow past their minimum checks; zero vertical checks. Gatekeeper called atcore/dc_resource.c:2873(dc_validate_stream). - (e) DCCG/clock source: not touched by this file (no clock-source interaction code present) β n/a.
- (f) globalsync / crc (
:1214-1382,:2094-2197):check_point - FLIP_READY_BACK_LOOKUP(:1300) can underflow only if the CRTC V_TOTAL register reads < 3 (hardware state, not user timing) β masked anyway. CRC window values are pure masked field writes (:2116-2157).disable_vga(:1797-1836) leavesaddr = 0on an unknowncontroller_id, butdce110_timing_generator_construct:2245derives the id asCONTROLLER_ID_D0 + instancewith instance bounded by the resource pool (β€ 6 pipes) β default case unreachable in practice.
Verification performed
- No amdgpu device in the guest β no runtime run; the module builds and the file's logic is fully source-traceable (all sinks masked register writes).
fix.diffapplied to the guest/usr/src; the completeamdgpumodule (which compilesdce110_timing_generator.c) rebuilt with-Werrorand linkedamdgpu.ko(BUILD_EXIT=0;fix_build.logβ full untrimmed build log)./usr/srcrestored pristine afterwards; guest reset with the clean-source snapshot.
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_testableApplied to the guest /usr/src; the complete amdgpu module (which compiles dce110_timing_generator.c) rebuilt with -Werror and linked amdgpu.ko (BUILD_EXIT=0, full log in fix_build.log). Runtime fix validation not testable: no AMD ASIC on this guest.
findings/poc/DF-4091/fix.diff, findings/poc/DF-4091/fix_build.log
Confirmed kernel references
- sys/dev/drm/amd/display/dc/dce110/dce110_timing_generator.c:1144
- sys/dev/drm/amd/display/dc/dce110/dce110_timing_generator.c:1154
- sys/dev/drm/amd/display/dc/dce110/dce110_timing_generator.c:656
- sys/dev/drm/amd/display/dc/dce110/dce110_timing_generator.c:679
- sys/dev/drm/amd/display/dc/core/dc_resource.c:2873
- sys/dev/drm/amd/display/dc/dm_services.h:133
Detail
Evidence (decisive lines)
VERDICT.md (full 6-item checklist), fix.diff, fix_build.log (full untrimmed amdgpu -Werror build log, amdgpu.ko linked)
PoC changes
n/a (untested)
Verified recommended fix
Reject timings whose active+borders exceed h_total/v_total and guard the back-porch subtraction in dce110_timing_generator_validate_timing.
Verdict
Low - hardware-gated, source-certain (per the dce110-family checklist instruction). dce110_timing_generator_validate_timing (:1109-1163, the CRTC gatekeeper called from dc_validate_stream at core/dc_resource.c:2873) computes h_blank (:1144-1146) and h_back_porch (:1154-1157) with u32 subtractions that wrap on inconsistent timings, so a timing with h_total < h_addressable+borders or h_sync_width > h_front_porch passes the minimums; there are no vertical checks at all. program_blanking (:656-657, :679) wraps identically and set_reg_field_value_ex (dm_services.h:133-141) masks the wrapped values into the H/V blank registers. All sinks in the file are masked MMIO writes to constant addresses; no kernel memory corruption and no division exist in the file. Impact ceiling: garbage CRTC timing on a real ASIC (display corruption / speculative pipe hang). Full-file checklist results in VERDICT.md (set_drr, test patterns, GSL/CRC, disable_vga all bounded/masked). Fix authored; the whole amdgpu.ko module rebuilt -Werror clean with it applied.
No comments yet.