# PoC DF-4565 — latent one-past-the-end array index in the TV flicker filter

`sys/dev/drm/radeon/radeon_legacy_tv.c:647-660`
(`radeon_legacy_tv_mode_set()`): the match loop over `SLOPE_limit[5]` has no
fallback when `flicker_removal` matches none of the five entries; the loop
then exits with `i == ARRAY_SIZE(SLOPE_limit)` and the subsequent
`SLOPE_value[i]` / `YCOEF_value[i]` / `YCOEF_EN_value[i]` reads (lines
652-660) run one element past the `[5]`-element arrays declared at lines
269-272. The garbage longs are folded into `tv_y_saw_tooth_cntl` /
`tv_y_fall_cntl` / `tv_y_rise_cntl` MMIO values.

**Unreachable with the current constants** (and therefore filed as Info /
hardening): `flicker_removal` is derived only from the fixed
`available_tv_modes[]` rows (`ver_total` ∈ {740, 706, 727, 742}) and the
NTSC/PAL line counts (525/625); the result is always 2 or 3, both of which
are present in `SLOPE_limit = {6,5,4,3,2}`. Every other input to the
function (`tv_std` from the DRM "tv standard" enum property, validated
0..8 by the DRM property machinery; `h_pos/v_pos/h_size` are zero-initialized
`kzalloc` state with no user-settable property in this tree) is static.

## Build / run

Not runnable: the audit guest has no AMD GPU (radeon never attaches), and
the path is unreachable with the compiled-in tables anyway. This pack
records the code defect and the recommended bound.

## Fix

Clamp the index after the loop:

```diff
 	for (i = 0; i < ARRAY_SIZE(SLOPE_limit); ++i) {
 		if (flicker_removal == SLOPE_limit[i])
 			break;
 	}
+	if (i >= ARRAY_SIZE(SLOPE_limit))
+		i = ARRAY_SIZE(SLOPE_limit) - 1;
```
