# DF-1297 — Divide-by-zero in ci_thermal_setup_fan_table (ci_smumgr.c)

**Severity:** Medium · **CWE:** CWE-369 (Divide By Zero)
**File:** `sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.c:2159-2166`

## Build & run (AMD-DRM latent bug — no AMD GPU on guest, harness proof)

```
./build.sh   # cc -O0 -Wall -o harness harness.c   (-O0 REQUIRED, see below)
./run.sh     # ./harness
```

## Expected output (bug present)

```
DF-1297 ci_thermal_setup_fan_table divide-by-zero harness
VBIOS usTMin=2500 usTMed=2500 usTHigh=9000  duty100=100
=> t_diff1 = usTMed-usTMin = 0   (kernel divides by this)
SIGFPE caught: integer divide-by-zero on t_diff1 == 0
In-kernel equivalent: CPU trap 0 (#DE) -> kernel panic
RESULT: divide-by-zero CONFIRMED at ci_smumgr.c:2165
```

After applying `fix.diff`, the harness would still fault (it replicates the
unpatched arithmetic) — the fix is validated by inspection + build of the
kernel module source. The kernel-level fix adds a `t_diff1==0 || t_diff2==0`
guard before the division.

## Why -O0

At `-O2` gcc sees integer div-by-zero as undefined behavior and (when it can
prove the zero at compile time) elides the `div` instruction. The real kernel
builds at `-O2` but reads the divisor at runtime from a parsed VBIOS struct
pointer, so gcc emits a real `div` → #DE trap → panic. `-O0` reproduces that
runtime division faithfully in userspace.

## Preconditions (kernel path)

All of: `PHM_PlatformCaps_MicrocodeFanControl` set + fan present +
`fan_table_start != 0` + `duty100 != 0`. Plus attacker control of the VBIOS
temperature fields (malicious/faulty ROM, VFIO passthrough, supply-chain).
See `VERDICT.md` for the full trace.
