# DF-4924 VERDICT — unreserved TMZ FRAME_CONTROL emission in the amdgpu_ib_schedule frame budget (gfx_v9_0 gfx ring)

**Status: not_reproduced (runtime)** — the kernel path is hardware-gated on
this guest; the arithmetic and write pattern are **harness-replicated
byte-exactly** and source-certain.

## Reproduced?

* **Kernel-side: no — only because the AMD hardware is absent.** The guest has
  a single Bochs std-VGA (chip 0x11111234), no 0x1002 PCI device, no
  /dev/dri, and no drm/amdgpu modules (env.txt). `amdgpu_ib_schedule()` on a
  gfx_v9_0 gfx ring requires an attached Vega10/Raven ASIC.
* **Harness-side: yes, deterministic** (run.log, run.2.log — identical):
  with the tree's exact constants (`emit_frame_size` breakdown = 160 dw with
  SOC15_FLUSH_GPU_TLB_NUM_WREG=4 / NUM_REG_WAIT=1 per soc15.h:31-32,
  `emit_ib_size`=4, `align_mask`=0xff, TMZ emit=2 dw), submissions overrun
  the reserved window by exactly 2 dwords for `num_ibs ∈ {24, 88, 152}` in
  the 1..200 sweep and for no other values — matching the closed-form rule
  `num_ibs ≡ 24 (mod 64)`. With the `+2` TMZ term added to the accounting
  (fix.diff), zero overruns for all 200 values.

## Root cause (path:line)

* Reservation: `amdgpu_ib_schedule()` computes
  `alloc_size = ring->funcs->emit_frame_size + num_ibs * ring->funcs->emit_ib_size`
  (sys/dev/drm/amd/amdgpu/amdgpu_ib.c:159-162) and `amdgpu_ring_alloc()`
  aligns it up to `align_mask` (amdgpu_ring.c:64-76) — 256 dw for gfx9.
* Emission: for any ring with `.emit_tmz` set — gfx_v9_0 gfx ring,
  gfx_v9_0.c:4780 — ib_schedule emits a 2-dword `PACKET3_FRAME_CONTROL`
  packet unconditionally (amdgpu_ib.c:231-232 → `gfx_v9_0_ring_emit_tmz`,
  two `amdgpu_ring_write()` calls).
* Accounting: the gfx funcs `emit_frame_size` sum (gfx_v9_0.c:4745-4764)
  contains every other emission site (COND_EXEC ×2, PIPELINE_SYNC, TLB flush
  wregs/reg-waits, VM_FLUSH + fence, GDS, double SWITCH_BUFFER, HDP flush,
  VGT flush, CE/DE META, CNTX_CTRL, HDP_INVL, FENCE ×2, SWITCH_BUFFER) but
  **no TMZ term**.
* Consequence mechanics: `amdgpu_ring_write()` (amdgpu_ring.h:276-283) logs
  `DRM_ERROR("writing more dwords to the ring than expected!")` when
  `count_dw <= 0` but writes the dword anyway, so the last 2 dwords of the
  frame land past the booked window: inside the ring BO (`buf_mask` masks the
  index — NOT a kernel-memory OOB) but in space belonging to the next
  submission, or — when wptr approaches rptr — on top of not-yet-consumed
  commands, corrupting the GPU command stream.

## Impact ceiling

* Every worst-case gfx CS job with `num_ibs ≡ 24 (mod 64)` (trivially
  chosen: number of AMDGPU_CHUNK_ID_IB chunks, amdgpu_cs.c:181-183) books
  256·k dwords and emits 256·k+2. Unprivileged DRI client; no races.
* Guaranteed: `count_dw` underrun + DRM_ERROR per submission; wptr drift of
  2 dwords per submission **accumulates** into subsequent submissions'
  space (the next `ring_alloc()` starts at the drifted wptr, so corruption
  is transiently overwritten — but at ring wrap the 2 dwords can land on
  unconsumed commands → GPU command corruption → ring hang → device reset).
* Contained in the ring BO (no kernel-memory write) — hence Low severity,
  DoS-class ceiling, cross-submission command-corruption potential.

## Fix validation

* `fix.diff` adds `2 + /* FRAME_CONTROL (TMZ) */` to gfx_v9_0.c
  `emit_frame_size`.
* Applied inside the guest's /usr/src (patch hunk @4759, clean), full
  `amdgpu.ko` module rebuilt under `-Werror` — EXIT=0, final
  `cc -r -o amdgpu.ko ... gfx_v9_0.o ...` link line present (fix_build.log).
* Harness A/B: baseline accounting → 3 overruns (n=24/88/152); fixed
  accounting → 0 overruns across the same sweep (run.log).
* Source reverted afterwards; guest gfx_v9_0.c sha256 back to baseline
  `119af8855ea0b484531066ee0a13cbc2c8005920abae895488991ff9d8a1a67c`
  (identical to the audit tree's file).
* Runtime kernel A/B impossible on this guest (no AMD GPU) → fix_status
  `not_testable` at runtime, arithmetic-validated at harness level.

## Not pushed further

A uid0 chain is not applicable: the overrun writes are masked inside the
ring BO (device memory mapping), so no kernel-memory write primitive exists.
The impact ceiling is GPU command corruption / DoS.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
