# DF-4732 VERDICT

## Status: `untested` — no AMD GPU on the audit guest; acquisition chain proven statically

## What was proven (static, line-cited)

1. **The lock is sleepable on this port.**
   - `sys/dev/drm/include/linux/spinlock_types.h:38` — `typedef struct lock spinlock_t;`
   - `sys/dev/drm/include/linux/spinlock.h:75-78` —
     `#define spin_lock_irqsave(lock, flags) ({ local_irq_save(flags); lockmgr(lock, LK_EXCLUSIVE); })`
   - `amdgpu_dm_irq.c:305` — the lock is initialized with
     `lockinit(&adev->dm.irq_handler_list_table_lock, "agdmihltl", 0, LK_CANRECURSE)`
     (a DFly sleepable lockmgr lock; upstream v4.17 has `spin_lock_init` here —
     confirmed by diff against torvalds/linux v4.17 during this audit).

2. **The ISR dispatch path acquires it.**
   - `sys/dev/drm/linux_irq.c:84-86` — `request_irq()` installs
     `linux_irq_handler` via `bus_setup_intr(..., INTR_MPSAFE, ..., &irq_entry->irq_lock)`
     with a `lwkt_serialize` — the handler runs in serialized interrupt-thread
     context.
   - `amdgpu_irq.c:189-199` → `amdgpu_irq_dispatch` (`:397-436`, no NULL
     `.process` guard — that is DF-4713's finding) → the sources registered by
     this file (`amdgpu_dm_irq.c:588-601`: `dm_crtc_irq_funcs`,
     `dm_pageflip_irq_funcs`, `dm_hpd_irq_funcs` — all three carry BOTH `.set`
     and `.process`, so this file does **not** hit the DF-4713 hole) dispatch to
     `amdgpu_dm_irq_handler` (`:476-495`).
   - `amdgpu_dm_irq_handler` → `amdgpu_dm_irq_immediate_work` (`:452`, takes
     `DM_IRQ_TABLE_LOCK`, runs handlers under it at `:464`) and
     `amdgpu_dm_irq_schedule_work` (`:427`, takes the lock to test
     `list_empty`). Both run in ithread context.

3. **The lock is held long enough in process context to make contention real.**
   - `amdgpu_dm_irq_suspend` (`:345-363`): holds the lock across
     `dc_interrupt_set()` for each HPD source — an MMIO read-modify-write per
     source (`irq_service.c:88-99`).
   - Any concurrent DCE interrupt (vblank/pflip storm during modeset, HPD
     glitch during suspend) takes the same lock from the ithread.

4. **Why sleeping in that context is fatal:** DragonFly lockmgr blocks via
   `tsleep` on contention; a serialized ithread must not sleep (it holds the
   interrupt serializer installed by `bus_setup_intr`), and the shim has also
   disabled local hardware IRQs (`local_irq_save` → `cpu_disable_intr`).
   Result ceiling: kernel panic ("sleep in ithread" assertion) or a wedged
   interrupt path → local DoS. This is a **DFly-port-specific divergence**
   (upstream's real spinlock is legal in hardirq).

## What was NOT demonstrated

No runtime reproduction: the guest has no AMD display adapter
(`pciconf`: only `vgapci0 chip=0x11111234` QEMU virtual VGA; no `/dev/dri`;
no drm kld — env.txt). The amdgpu module cannot bind, so neither the ISR path
nor the suspend race can be triggered. No kernel was built for the same reason
(a single-fix kernel build proves nothing without the device).

## Exploit chain (theoretical ceiling)

Local unprivileged user in a desktop session on AMD graphics hardware:
generate page-flip/vblank interrupt pressure (compositing) or hotplug events
(DP cable / USB-C dock emulation by root) while the system enters
suspend/resume (`amdgpu_dm_irq_suspend` holds the table lock across MMIO) →
GPU ithread blocks in `lockmgr` → panic. Impact: local DoS (panic). No path to
privilege escalation identified: the corruption is control-flow-internal (no
attacker-controlled data crosses the boundary).

## Fix validation

`fix_status: not_testable` (hardware absent). `fix.diff` converts the table
lock to a true `struct spinlock` with `crit_enter()`/`spin_lock()` in the
DM_IRQ_TABLE_LOCK macros — matching upstream's non-sleeping semantics and the
file's actual usage (no recursion on this lock exists; CANRECURSE was
unnecessary — audited: no high-context handler re-acquires the table lock).

## Bottom line

Code-certain protocol violation introduced by the port (sleepable lockmgr +
forced irq-disable inside the GPU ithread), DFly-specific, panic ceiling under
an interrupt-vs-suspend race on AMD hardware; untestable on this guest for
lack of the device.

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