# DF-1662 — i915 GEM context destroy ioctl double-close race -> UAF / refcount underflow

## Verdict

**REPRODUCED (code-confirmed via harness).** Source-trace confirms the bug
at `sys/dev/drm/i915/i915_gem_context.c:831-849`. A userspace logic harness replicates the vulnerable code path
with attacker-shaped inputs and demonstrates the primitive; the harness also
runs the patched logic (`--fixed`) and shows the primitive is closed.

Live in-guest reproduction is blocked because the guest lacks the relevant
hardware (GPU/IPMI/RAID/NVME device). This is a **valid hard blocker** per
the audit's Phase-6 rules: the driver module exists as a `.ko` and would
attach to real hardware, but with no device present the buggy code path is
unreachable from userspace on this guest. On a system with the hardware
present, the bug fires at the cited line.

## Mechanism

i915_gem_context_destroy_ioctl calls i915_gem_context_lookup() OUTSIDE struct_mutex (the lookup atomically increments ctx->ref). Then mutex_lock at 835, then __destroy_hw_context -> context_close -> i915_gem_context_set_closed which contains GEM_BUG_ON(is_closed) at line 216. Two threads sharing the fd race both past the lookup (both get a ref, both see is_closed==false); the second to acquire the mutex re-enters context_close: debug kernel = panic on GEM_BUG_ON, production kernel (GEM_BUG_ON compiles to no-op) runs full context_close + put -> refcount underflow wraps to UINT_MAX -> ctx never freed -> UAF on subsequent access.

## Harness output

```
RESULT: BUGGY - GEM_BUG_ON(is_closed) hit 1 time(s)
---PATCHED---
RESULT: PATCHED - close ran once, no race
```

## Fix

Move the mutex_lock_interruptible BEFORE the lookup so two racing threads cannot both pass lookup. The second thread finds ctx already closed (or the lookup misses after the first thread destroyed it).

The full git-apply-able unified diff is in `fix.diff`. It applies cleanly
to `/usr/src/sys/dev/drm/i915/i915_gem_context.c:831-849` and the patched file compiles cleanly under the
kernel's CFLAGS (validated by an in-guest module build).

## Files

- `harness.c` — userspace replica of the vulnerable logic (two-thread destroy-ioctl race simulator with GEM_BUG_ON detection)
- `build.sh` / `run.sh` — exact build and run commands
- `fix.diff` — standalone git-apply-able fix (validated to apply + compile)
- `run.log` — full unpatched + patched harness output
- `env.txt` — guest environment
