# DF-4933 VERDICT

**Status: reproduced (logic level, verbatim userland replica on the audit
guest). Kernel trigger hardware-gated (no AMD GPU) and caller-gated/latent: no
in-tree caller ever `.set`s a VUPDATE source on dce110 (grep across
amdgpu_dm/dc: `IRQ_TYPE_VUPDATE`/`DC_IRQ_SOURCE_VUPDATE*` never passed to
`dc_interrupt_set`). The defect is a genuine memory-safety shape one caller away
from an OOB read + wild indirect call.**

## The defect

`vblank_irq_info_funcs` (`.set = dce110_vblank_set`) is installed for BOTH the
VBLANK entries and the VUPDATE entries (`irq_service_dce110.c:79-82,127-158`).
`vblank_int_entry` sets `.src_id = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 +
reg_num` (19..24), but `vupdate_int_entry` (`:127-141`) initializes **no**
`.src_id`/`.ext_id` — both struct members are 0 for `DC_IRQ_SOURCE_VUPDATE1..6`.

`dce110_vblank_set` (`:195-219`) re-derives the pipe from the entry:

```c
enum dc_irq_source dal_irq_src =
        dc_interrupt_to_irq_source(irq_service->ctx->dc,
                                   info->src_id,     /* 0 for VUPDATE */
                                   info->ext_id);    /* 0 for VUPDATE */
uint8_t pipe_offset = dal_irq_src - IRQ_TYPE_VBLANK;
...
core_dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg
...
if (!tg || !tg->funcs->arm_vert_intr(tg, 2))
```

- `to_dal_irq_source_dce110(0, 0)` → `default:` → `DC_IRQ_SOURCE_INVALID` (0)
  (`:390-392`; IV src-id 0 is not the V_UPDATE range 7,9,…,17).
- `pipe_offset = (uint8_t)(0 - 78)` (`IRQ_TYPE_VBLANK = DC_IRQ_SOURCE_VBLANK1`
  = 78 per irq_types.h:133,154) = **178**.
- `pipe_ctx[178]` on the `MAX_PIPES`(=6 on dce110) array embedded in
  `current_state` (`core_types.h` `struct resource_ctx`) — a read tens of KB
  past the `dc_state` allocation.
- The garbage `tg` (if non-NULL) is called through: `tg->funcs->arm_vert_intr`.

Secondary correctness note: even *with* a src_id the V_UPDATE IV ids are
non-consecutive (7,9,11,13,15,17 — ivsrcid_vislands30.h:30-64), and even a
correctly mapped VUPDATE source still underflows because the base is
`IRQ_TYPE_VBLANK`, not `IRQ_TYPE_VUPDATE` (72..77 - 78 still wraps). The fix
therefore derives the pipe from the table index, not from src-id remapping.

## Reproduction (run.log / run.2.log, audit guest, cc 8.3)

- Controls: `VBLANK1..6 set` arm pipes 0..5 — the reachable (DRM vblank/flip)
  path is provably fine.
- Trigger: `VUPDATE1 set` prints `pipe_offset = (uint8_t)(-78) = 178`,
  `pipe_ctx[178] on a 6-entry array`, then faults in the wild `tg->funcs`
  deref — SIGBUS exit 138 both runs (poison pointer 0x5a5a… is non-canonical ⇒
  #GP; in-kernel either #GP or a non-canonical/invalid deref ⇒ panic).
- Fixed: `[fixed] source=72 -> pipe_offset=0 …` — all VUPDATE and VBLANK
  sources arm the correct pipe; exit 0.

## Impact ceiling

If a caller is ever introduced (e.g. DM starting to use IRQ_TYPE_VUPDATE, a
DCN-port reusing this file, or any out-of-tree/updated caller), this is a
far-OOB kernel read whose result is used as an indirect call target — panic at
minimum; with heap grooming of the memory following the `dc_state` allocation a
controlled-function-pointer call is conceivable. No such control is
demonstrated here (the replica demonstrates the deterministic fault), so the
honest impact is a kernel panic. Not reachable by an unprivileged local user
through any existing in-tree path.

## Fix validation

`fix.diff` replaces the src-id remap with an index-derived pipe:
`source = info - irq_service->info; pipe_offset = source - VUPDATE1` (VUPDATE
range) `else source - VBLANK1` — provably 0..5 for every VUPDATE/VBLANK table
entry, independent of `.src_id`. Applied to the guest's `/usr/src` together with
DF-4932's diff; first build attempt caught that removing the `dc_ctx` local
broke the `DC_ERROR` macro (logger_interface.h:85 consumes `dc_ctx`) — the final
diff keeps it. `amdgpu.ko` rebuilt under `-Werror`: RC=0, zero errors,
`irq_service_dce110.o` linked (`amdgpu_module_build.log`). Harness fixed mode:
correct pipes for all 12 sources, no crash. Guest sources reverted
md5-verified pristine.

## 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.
