# DF-3735 — `r600_pm_init_profile` hardcodes clock-mode indices without validating `num_clock_modes` — OOB heap read in the default PM profile

**File:** `sys/dev/drm/radeon/r600.c:680-763` (consumer sites r600.c:771, radeon_pm.c:181-199)
**Class:** kernel OOB heap read — CWE-125 / CWE-1284
**Severity:** Medium · **Confidence:** likely
**Bucket:** kernleak

## Build / Run / Expected

Kernel-internal PM path — no userspace trigger exists without a physical
r6xx discrete GPU carrying a PowerPlayInfo frev1/2 BIOS (single clock mode
per state). The audit guest is virtio-only and its kernel build ships no
`radeonkms.ko` (`env.txt`). Verification is source-level (`VERDICT.md`) plus
the guest presence check:

```sh
dfbsd-qemu/vm.sh run_root 'ls /boot/kernel/radeonkms.ko; pciconf -l | grep 1002'
```

**Expected on real hardware** (e.g. RV630/RV635/RV670, frev1/2 PowerPlay,
≥2 power states, display connected): on the first
`radeon_pm_compute_clocks()` after a modeset, the DEFAULT profile yields
`requested_clock_mode_index = 2` while the selected power state's
`clock_info` allocation holds exactly **one** element →
`power_state[ps].clock_info[2].sclk/.mclk` and `.voltage` are read two
elements past the allocation; garbage values are programmed as GPU engine
clock, memory clock and (VOLTAGE_SW) voltage.

## Trigger conditions

1. Non-IGP, non-R600 r6xx/r7xx discrete ASIC (`r600_pm_init_profile` else
   branch, `r600.c:679`) — wired to RV610..RV770-family asic blocks
   (`radeon_asic.c:987,1073,1272,1392`).
2. `num_power_states < 4` (`r600.c:680`) and ≥ 2
   (`radeon_pm.c:1735` guard).
3. PowerPlayInfo frev 1/2 BIOS → every state: `num_clock_modes == 1`,
   1-element `clock_info` allocation (`radeon_atombios.c:2126-2133`).
4. `active_crtc_count > 0` (display running) → DEFAULT profile's
   `dpms_on_cm_idx = 2` is applied (`radeon_pm.c:138-143`).

No sysfs interaction and no DYNPM needed — `PM_PROFILE_DEFAULT` is the
out-of-the-box profile (`radeon_pm.c:1359`), and
`radeon_pm_compute_clocks_old` calls
`radeon_pm_update_profile()+radeon_pm_set_clocks()` for PM_METHOD_PROFILE
(`radeon_pm.c:1753-1756`), which is the default method on DragonFly when DPM
is off (`radeon_pm.c:1584-1587`).

## Fix

`fix.diff` — clamp the profile-initialized clock-mode indices to each target
power state's `num_clock_modes - 1` at profile-init time. Never applied to
`sys/`; authored against the read-only tree.

## Artifacts

- `VERDICT.md` — full source-level proof
- `run.sh`, `run.log`, `env.txt` — guest module/hardware presence check
- `fix.diff` — proposed fix
- `manifest.json`, `verdict.json`
