# DF-3682 — Divide-by-zero (kernel panic) in `drm_gtf_mode_complex()` via crafted-EDID secondary-GTF parameters

## What

`sys/dev/drm/drm_modes.c:484-485` (reached from `sys/dev/drm/drm_edid.c:2188-2193`):

```c
ideal_duty_cycle = GTF_C_PRIME * 1000 - (GTF_M_PRIME * 1000000 / hfreq_est);
hblank = total_active_pixels * ideal_duty_cycle / (100000 - ideal_duty_cycle);
```

`GTF_M`, `GTF_2C`, `GTF_K`, `GTF_2J` are copied **unvalidated** from a
sink-supplied EDID monitor-range descriptor (bytes r[13..17]) by
`drm_gtf2_m/2c/k/2j()` (`drm_edid.c:2026-2055`). With

* `r[14]=r[15]=0`   → `GTF_M = 0`     → `GTF_M_PRIME = 0`
* `r[13]=200, r[17]=200` → `GTF_C_PRIME = ((200-200)*K/256 + 200)/2 = 100`

`ideal_duty_cycle` becomes **exactly 100000**, the divisor
`100000 - ideal_duty_cycle` becomes **zero**, and the kernel takes a
divide error (#DE on x86) → **panic**. Deterministic, base-block-only EDID.

## Reachability (line-level trace)

1. Sink supplies crafted EDID over DDC/AUX (`drm_do_get_edid`).
2. `drm_add_edid_modes` (`drm_edid.c:4729`) → `add_standard_modes` (4770).
3. `drm_mode_std` (`drm_edid.c:2095`): std-timing pair `{208, 0x00}` decodes
   to 1912x1195@60; `standard_timing_level()` (2061) returns `LEVEL_GTF2`
   because a DTD with `r[3]==0xFD && r[10]==0x02` exists (rev≥2, feature
   bit DRM_EDID_FEATURE_DEFAULT_GTF clear).
4. `case LEVEL_GTF2` (`drm_edid.c:2177-2194`): first `drm_gtf_mode()`
   succeeds; `drm_mode_hsync(mode) (~75 kHz) > drm_gtf2_hbreak() (=2, r[12]=1)`
   → `drm_gtf_mode_complex(dev, 1912, 1195, 60, 0, 0, M=0, 2C=200, K=128, 2J=200)`.
5. `drm_modes.c:480-485`: `C'=100, M'=0 → ideal_duty_cycle == 100000`
   → `/ 0` → panic.

No DMT hit (1912x1195 is not a DMT mode), no dedup conflict (DTD1 carries
pixel_clock=0 so no detailed modes were added first), `bad_std_timing()`
does not match — every precondition is satisfiable with a 128-byte
checksum-valid base block (`evil_edid.bin`).

## Reproduce (on the DragonFly guest)

The QEMU guest is **virtio-only** (`/dev/dri` absent, no drm kld, no GPU), so
the in-kernel trigger cannot be executed there. What *is* executed is the
**verbatim kernel function**: `gtf_body.inc` is a mechanical byte-for-byte
extraction of `drm_gtf_mode_complex()` from `sys/dev/drm/drm_modes.c`
(git 6cc80ee9; guest `/usr/src` copy md5-identical:
`ce51a6174062d43b24b7296cc0b3bc1e`). Only `struct drm_device` /
`struct drm_display_mode` and `drm_mode_create()`/`drm_mode_set_name()` are
stubbed; **every arithmetic statement is unmodified**.

```
./dfbsd-qemu/vm.sh run_root 'sh /tmp/build.sh'   # cc -O2 both harnesses
./dfbsd-qemu/vm.sh run_root 'sh /tmp/run.sh'     # baseline + 3x + fix test
```

Expected (observed):

```
baseline exit=136   (128+SIGFPE — integer divide trap; kernel: #DE → panic)
run1..run3 exit=136 (deterministic)
fix test exit=0     ("returned NULL (rejected bogus GTF2 params) -> fix OK")
```

## Files

| file | role |
|---|---|
| `gtf_body.inc` | verbatim extraction of `drm_gtf_mode_complex` from the audit tree |
| `gtf_kernel_extract.c` | harness: EDID byte decoding + verbatim function (baseline trap) |
| `gtf_fix_test.c` / `gtf_body_fixed.inc` | same, with the proposed fix guard (no trap) |
| `gen_edid.py` → `evil_edid.bin` | the malicious 128-byte EDID base block (valid checksum) |
| `gtf_div0.c` | independent re-derivation harness (same trap; early confirm) |
| `build.sh` / `run.sh` | exact commands run on the guest |
| `build.log` / `run.log` | full untrimmed guest output |
| `env.txt` | guest environment + source-identity proof |
| `fix.diff` | the fix (guard `ideal_duty_cycle`), never applied to `sys/` |

## Fix

See `fix.diff` — reject degenerate GTF2 parameters before the division
(`ideal_duty_cycle <= 0 || ideal_duty_cycle >= 100000` → destroy mode,
return NULL; both call sites already handle NULL).
