# DF-1253 — uint32 underflow in vega20_apply_clocks_adjust_rules (count-1 wraps to UINT32_MAX)

## Verdict
**SOURCE-CONFIRMED (real bug), INCONCLUSIVE at runtime** — the `amdgpu.ko` module is not loaded (no AMD Vega20 GPU in the QEMU guest) and is not in the GENERIC kernel, so the underflow path is dormant. Fix authored and compile-validated.

## Mechanism (source trace)
`vega20_apply_clocks_adjust_rules()` iterates over the MCLK latency table using a `uint32_t count - 1` loop bound with no zero-guard:

- `sys/dev/drm/amd/powerplay/hwmgr/vega20_hwmgr.c:3095-3104`:
  ```
  if (disable_mclk_switching) {
      dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value;
      for (i = 0; i < data->mclk_latency_table.count - 1; i++) {     /* <- UNDERFLOW */
          if (data->mclk_latency_table.entries[i].latency <= latency) {
              if (dpm_table->dpm_levels[i].value >= ...) { ... }
          }
      }
  }
  ```
- `data->mclk_latency_table.count` is `uint32_t` (`vega20_hwmgr.h:267`), default 0 after kzalloc. It is set non-zero **only** by `vega20_get_memclocks()` (`vega20_hwmgr.c:2435`). If `vega20_apply_clocks_adjust_rules` runs before `vega20_get_memclocks` populates the table, `count - 1` wraps to `0xFFFFFFFF` ⇒ the loop iterates ~4 billion times, reading `entries[i]` and `dpm_levels[i]` OOB past their `MAX_REGULAR_DPM_NUMBER=16` arrays (`vega20_hwmgr.h:159,268`).
- `disable_mclk_switching` is `true` when `1 < num_display && !multi_monitor_in_sync` (multi-monitor out of sync) or `vblank_too_short` (`vega20_hwmgr.c:3037-3039`) — a plausible state on a multi-monitor Vega20 system when display config changes.
- The same `count - 1` OOB pattern also appears at lines 3045/3047/3069/3071/3096/3108 for `dpm_table->count`, though those are guarded by `vega20_setup_default_dpm_tables` setting `count >= 1` (`vega20_hwmgr.c:598`).

## Why not reproduced at runtime
- `amdgpu.ko` is **not loaded** on the guest and is **not in X86_64_GENERIC**.
- Requires an AMD Vega20 GPU (Radeon VII / Vega 20); QEMU guest has no AMD GPU.
- On real hardware, an unprivileged user changing display config (hotplug, mode set) could influence `num_display`/`multi_monitor_in_sync` and trigger the underflow if the power-management state machine calls `apply_clocks_adjust_rules` before `get_memclocks`.

## Fix (fix.diff, compile-validated)
1. Guard `dpm_table->count == 0` before the `count - 1` accesses in the `disable_mclk_switching` and `nb_pstate_switch_disable` blocks (skip via a `goto skip` / early return).
2. Rewrite the latency loop bound as `i + 1 < data->mclk_latency_table.count` (no underflow when count is 0) and add a hard `i < MAX_REGULAR_DPM_NUMBER` cap as defense-in-depth.

The patched `vega20_hwmgr.c` compiles cleanly with gcc 8.3, `-Werror`, no warnings.

## Realistic impact ceiling
Kernel heap OOB read (entries[]/dpm_levels[] past [16]) of up to ~4B iterations on a Vega20 system when MCLK switching is disabled before the latency table is populated — a DoS (hang/panic from OOB read or page fault) and potential info leak. On this guest: **not reachable** (no AMD GPU).
