# DF-4373 — Divide-by-zero (#DE panic) in dce_transform_get_max_num_of_supported_lines

## What
`sys/dev/drm/amd/display/dc/dce/dce_transform.c:710` divides
`max_pixels_supports / pixel_width` guarded only by `ASSERT(pixel_width)`
(:675), and ASSERT in this tree compiles to `WARN_ON` only
(`sys/dev/drm/amd/display/dc/os_types.h:48` — `#define ASSERT(expr) WARN_ON(!(expr))`).
Execution continues into the integer division; `pixel_width == 0` produces a
divide-error fault in kernel mode → kernel panic (local DoS).

## Who can trigger
Any DRM master holder — on a desktop/seat system that is the ordinary
unprivileged session user (logind gives the session DRM master). A
`DRM_MODE_ATOMIC_TEST_ONLY` commit suffices: the division happens on the
atomic-check path (`dc_validate_global` → `resource_build_scaling`).

## Concrete trigger (real DCE100/110/112/120 hardware)
1. CRTC: any mode, e.g. 640x480.
2. Plane: source ≥ 16x16 (e.g. 640x480 dumb buffer), CRTC_X = 640 (== mode
   width: flush off the right edge), CRTC_Y = 0, CRTC_W = 1, CRTC_H = 480.
3. Submit atomic commit (TEST_ONLY is enough).

Why this is accepted by every check:
- `fill_rects_from_plane_state` (amdgpu_dm.c:2210-2238) never clips to the
  CRTC and only rejects zero-sized rects; `clip_rect = dst_rect`.
- `dc_validate_plane` (dc_resource.c:2891-2897) validates *pixel format only*.
- `calculate_viewport` (dc_resource.c:543): `viewport.width = clip.width *
  surf_src.width / dst_rect.width` = `1 * 640 / 1` = 640 — viewport is in
  SOURCE pixels, so the `viewport.width < 16` guard (dc_resource.c:1122)
  PASSES even though the visible recout is empty.
- `calculate_recout` (dc_resource.c:631-643): `recout.x = 640`; clamp at
  :639-643 gives `recout.width = (0 + 640) - 640 = 0` exactly.
- `dce_transform_get_optimal_number_of_taps` (dce_transform.c:896-907):
  `prescaler_on` is hard-coded true at construction (:1359); `viewport.width
  (640) > recout.width (0)` → `pixel_width = recout.width = 0`.
- `dce_transform_get_max_num_of_supported_lines` (:667-711): ASSERT no-ops →
  division by zero at :710.

An underscan variant also works (connector "underscan hborder" property,
range 0..128 — amdgpu_display.c:605-607, stream dst inset at amdgpu_dm.c:2502-2506):
a 1px-wide plane fully inside the CRTC with hborder 128 on a 640-wide mode
gives `recout.width = 1*512/640 = 0` at dc_resource.c:637-638.

## Build / Run (probe)
- `./build.sh && ./run.sh` — compiles the probe and attempts to open
  `/dev/dri/card0`. On machines without an AMD DC GPU it reports the device
  absence (this is what happens on the audit QEMU guest, which has only QEMU
  std VGA, vendor 0x1234).

## Expected on real hardware
Immediate kernel panic: `Fatal trap 12: divide error fault...` (actually trap 0
#DE) in `dce_transform_get_max_num_of_supported_lines`, during
`amdgpu_dm_atomic_check`.

## Files
- `trigger_df4373.c` — standalone probe / ioctl sketch
- `VERDICT.md` — full static proof chain and honest reproduction status
- `fix.diff` — one-guard fix (returns 0 = "no lines supported" so validation fails cleanly)
