{
  "finding_id": "DF-4506",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "i915_gem_context.c performs its handle->context lookups (destroy :831, getparam :855, setparam :901, reset_stats :981) with no lock, inheriting Linuxs assumption that idr_find() is RCU-safe. On DragonFly rcu_read_lock() is a no-op and idr_find() takes no token, while idr_grow() (reachable from the same files create path :355) kfrees the old node array synchronously \u2014 an unprivileged render-node user racing create against any lookup ioctl gets a UAF read that returns attacker-groomed contents as a struct i915_gem_context * (feeding kref_get_unless_zero, set_bit, list_del_init write primitives). Verified on the guest: amplified runs returned the canary pointer in 20/20 and 9/10 rounds; native unamplified 500-round stress PANICKED the kernel in idr_find+0x48 (fault 0xc88 = nodes[200].allocated); fix.diff (defer the kfree 1s, mirroring the shims kfree_rcu delay line) rebuilt under identical conditions gave 0 captures and no panic across 1,598,684 native finds. Full uid=0 chain not assembled: the guest has no Intel GPU, so the i915 ioctl surface itself is not exercisable here.",
  "exploit_chain": "unpriv user opens render node; T1 spams DRM_IOCTL_I915_GEM_CONTEXT_CREATE until >255 live contexts force idr_grow (kfree of old 4080B node array) while grooming that size class with controlled contents; T2 simultaneously spams CONTEXT_DESTROY/GETPARAM/SETPARAM/RESET_STATS whose lockless i915_gem_context_lookup walks the freed array; won race returns crafted ctx pointer -> kref_get_unless_zero write at controlled offset; on destroy path __destroy_hw_context -> context_close -> set_bit(ctx->flags), list_del_init(ctx->hw_id_link) unlink writes, lut_close list/radix walks on controlled pointers -> arbitrary write -> cred overwrite -> uid=0. Demonstrated on guest: controlled UAF read (canary) amplified 20/20+9/10, native panic in idr_find; pointer-to-write chain analyzed at i915_gem_context.c:278-299/395-400 but not executed end-to-end (no i915 hw on guest).",
  "evidence": "panic.txt (Fatal trap 12, Stopped at idr_find+0x48: movl 0x8(%rbx),%edx, VA 0xc88=nodes[200].allocated); run.log (amplified canary captures 20/20 then 9/10); run.fixed.log (0 captures, 1,598,684 native finds, guest alive after fix); idr_race.c + amplifier.diff + fix.diff; VERDICT.md for the full narrative",
  "kernel_refs": [
    "sys/dev/drm/i915/i915_gem_context.c:831",
    "sys/dev/drm/i915/i915_gem_context.c:855",
    "sys/dev/drm/i915/i915_gem_context.c:901",
    "sys/dev/drm/i915/i915_gem_context.c:981",
    "sys/dev/drm/i915/i915_gem_context.c:355",
    "sys/dev/drm/i915/i915_drv.h:3288-3306",
    "sys/libkern/linux_idr.c:515-528",
    "sys/libkern/linux_idr.c:420-461",
    "sys/dev/drm/include/linux/rcupdate.h:46-56",
    "sys/dev/drm/include/linux/preempt.h:33",
    "sys/dev/drm/linux_rcu.c:161-184"
  ],
  "poc_changes": "no orchestrator seed existed; pack built from scratch: KLD reproducer (producer=fill+grow+canary-realloc, consumer=lockless idr_find, canary detector), guest-only sysctl-gated race amplifier in idr_find, and the real fix.diff (deferred kfree via callout). Guest quirks handled: no buildworld (used nativekernel), kmod.mk path, -Wcast-qual, DF kthread_create signature, and reader lwkt_yield() to avoid starving the non-preemptive scheduler.",
  "attempts": 8,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #2: Sun Sep 20 23:21:09 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "runtime_sec": 3900,
  "guest_dirty": 0,
  "build_cmd": "cd /usr/src && make -j6 nativekernel KERNCONF=X86_64_GENERIC && make installkernel KERNCONF=X86_64_GENERIC; cd /root/idr_race && make SYSDIR=/usr/src/sys",
  "run_cmd": "kldload /root/idr_race/idr_race.ko; sysctl debug.idr_find_pause=3; sysctl debug.idr_race.run=20; sysctl debug.idr_race.captures; sysctl debug.idr_find_pause=0; sysctl debug.idr_race.run=-500",
  "code_hash": "49262e68a94f1201e730cd369a556e00c4d8ad793fba5e73adc2aff2c50d3eb0",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff defers the kfree of replaced/destroyed IDR node arrays by 1s via callout, mirroring the drm shims own kfree_rcu delay-line convention. Baseline kernel: 20/20+9/10 amplified canary captures and a native-window kernel panic in idr_find+0x48. Patched kernel under identical amplified conditions: 0 captures/0 anomalies; 3x native stress (1,598,684 finds): no panic, guest alive. fix_status=fixed.",
  "fix_evidence": "run.fixed.log (0 captures after fix under identical conditions), build.log (both kernel builds), panic.txt (baseline panic)",
  "notes": "intel_audio.c audited clean in the same run (component ops entirely #if 0 dead code in this port). The i915-side hardening alternative (take struct_mutex around lookups) also closes DF-1662s window; shim-side deferred free protects every lockless idr user (drm_gem, drm_syncobj, amdgpu_ctx, drm_mode_object use the same pattern).",
  "recommended_fix": "Defer kfree() of IDR node arrays in idr_grow()/idr_destroy() by ~1s (callout), matching the drm shims kfree_rcu delay-line convention; optionally also serialize i915 context lookups under dev->struct_mutex."
}