# 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:

```c
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_blank` underflows to ~4 G and
  sails through the `< 56` check.
- If `h_sync_width > h_front_porch`, `h_back_porch` underflows and passes
  `< 4`.
- There are **no vertical checks at all** (no `v_addressable` fit, no
  v-porch minimums).

The accepted timing is later programmed by
`dce110_timing_generator_program_blanking()` / `program_timing_generator()`:

```c
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 ≤ htotal` etc.), but `dc_validate_stream` exists as
  defense-in-depth and is bypassable by any internal producer that adjusts
  timings (e.g. DRR/FreeSync v_total adjustments in `set_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`).
