# DF-3740 — Stack buffer overflow in radeon_atom_get_mclk_range_table via uncapped num_entries fill of mclk[16]

**Severity**: High · **CWE**: CWE-787 / CWE-121 Out-of-bounds Write (stack) · **File**: sys/dev/drm/radeon/radeon_atombios.c:3938-3946

## What this is
Source-certain kernel-stack overflow. radeon_atom_get_mclk_range_table() computes num_entries=(u8)((usModuleSize-32)/24) from the BIOS VRAM module's u16 usModuleSize and copies num_entries BIOS u32s into mclk[MAX_AC_TIMING_ENTRIES=16] (radeon_mode.h:637-649) with NO bound between the u8 count (up to 255 after truncation) and the 16-slot array. The ONLY caller (cypress_dpm.c:1075-1089, cypress_get_memory_clock_range_table) passes a stack local 'struct atom_memory_clock_range_table range_table = {0}' — so up to 239 BIOS-chosen u32s (956 B) are written past a 68-byte stack object (return address / caller frame). Harness on guest: usModuleSize=0xFFF0 -> num_entries=168 -> 152 OOB u32 writes (608 B past struct end). A truncation underflow (usModuleSize < 32) yields arbitrary num_entries as well. Downstream cypress_retrieve_ac_timing_for_all_ranges() also READS mclk[i] for i<num_entries (OOB stack reads). Not executable in-kernel on this guest (no AMD GPU).

## Reproduce
```
./build.sh    # cc -O1 -g -Wall -o <bin> harness_mclk.c   (DragonFly guest, cc 8.3)
./run.sh      # expected: num_entries=168 vs mclk[16]; 152 OOB u32 writes (608 bytes) of VBIOS-chosen data; exit_code=0
```
The harness replicates the kernel parse arithmetic VERBATIM (cited path:line) against a
synthetic crafted-VBIOS buffer with canary-guarded destinations.

## Guest / environment
Guest has NO AMD/radeon GPU (virtio-only); /boot/kernel/radeon.ko exists (code shipped in the default install) but cannot attach, so the kernel code path is unreachable at runtime on this guest. Evidence is source-level certainty (path:line traced) plus a verbatim-arithmetic userland harness compiled and executed on the guest (build.log/run.log).
See env.txt (uname, cc, kldstat, /boot/kernel/radeon.ko presence).

## Fix
reject/clamp num_entries to MAX_AC_TIMING_ENTRIES — see fix.diff (authored after verification; never applied to sys/).
