# DF-3688 — Unbounded sprintf loop in smu7_print_clock_levels overflows the 4096-byte sysfs page buffer once the VBIOS DPM count exceeds ~233

**File:** `sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c` (pass 2, GLM 5.3 re-audit)
**Severity:** Low | **CVSS:** CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:H | **CWE:** CWE-787 Out-of-bounds Write; CWE-120 Buffer Copy without Checking Size of Input | **Confidence:** certain (source)

## What this is

Source-certain output-budget overflow, precondition shared with DF-1166 (VBIOS dep count > 8 is unvalidated); runtime-inconclusive on this guest (no AMD GPU). smu7_print_clock_levels sprintf()s one line per DPM level into the caller's sysfs page buffer (amdgpu_pm.c amdgpu_get_pp_dpm_sclk/mclk/pcie pass the raw 4096-byte kernfs buf; pp_od_clk_voltage likewise). The loops run to sclk_table->count / mclk_table->count / pcie_table->count / odn_*->num_of_pl - all ultimately the unvalidated VBIOS u8 count (up to 255). Measured on the guest with the exact format strings: 255 PP_PCIE lines = 4481 bytes and 255 PP_SCLK lines with u32-scale clocks = 4481 bytes, both overflowing PAGE_SIZE; the per-line reads dpm_levels[i] for i >= 8 are themselves OOB reads of the dpm_levels[8] arrays. Impact: heap overflow of the kernfs page on an UNPRIVILEGED sysfs read once the count is corrupted by a crafted VBIOS; ~385 bytes past the page.

## Reproduce (harness on the audit QEMU guest)

```
scp -F dfbsd-qemu/config sprintf_budget.c dfbsd-maxx:/tmp/DF-3688/
ssh -F dfbsd-qemu/config dfbsd-maxx 'cd /tmp/DF-3688 && cc -Wall -O0 -o t sprintf_budget.c && ./t'
```

Expected: the run prints the confirmed-primitive line (`RESULT: ... CONFIRMED ...`).
See `run.log` (and `run.2.log` where present) for the decisive captured output,
`build.log` for the guest toolchain transcript, `env.txt` for the guest environment
(virtio-only, **no AMD GPU** — `pciconf -l` shows only 0x1237/0x1111 QEMU devices;
`drm.ko`/`amdgpu.ko` exist in /boot/kernel but are not loaded and have no hardware
to bind), which is why the in-kernel trigger itself is inconclusive on this guest.

## Fix

`fix.diff` (authored against the read-only sys/ tree; never applied there).
