DF-4568 / verdict.json
{ "finding_id": "DF-4568", "status": "untested", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Static verdict, defect proven at source level: guc_disable_communication() (intel_uc.c:226-237) calls intel_guc_ct_disable() at :231 \u2014 which frees and unmaps the shared CT page via ctch_close (intel_guc_ct.c:898) -> ctch_fini -> i915_vma_unpin_and_release(I915_VMA_RELEASE_MAP) (intel_guc_ct.c:214-218) \u2014 BEFORE gen9_disable_guc_interrupts() at intel_uc.c:233 masks+synchronize_irq()s the GuC events (i915_irq.c:555-567), and before guc->handler stops pointing at intel_guc_to_host_event_handler_ct (only switched at intel_guc_ct.c:902, after the free). A GuC event asserted in that window dispatches the CT handler into ct_process_host_channel (intel_guc_ct.c:815-840) which reads and writes through the freed descriptor (desc->head write at :628, is_in_error write at :838) \u2014 interrupt-context UAF read+write. The ctch_is_open() guard (:822) is an unlocked check-then-use on ctch->vma and cannot close the window. Unreachable on this tree: no platform ever sets info.has_guc_ct (intel_device_info.h:94 declared; i915_pci.c:469/:520 set only .has_guc), and enable_guc defaults to 0 (i915_params.h:49), so intel_guc_ct_disable can never run here; callers are privileged driver-lifecycle paths anyway. Filed as Info hardening; no runtime PoC possible (guest GPU is QEMU bochs std-VGA, no i915 device, and the window is not attacker-timed).", "exploit_chain": "", "evidence": "findings/poc/DF-4568/VERDICT.md (ordering diagram with path:line); decisive lines: intel_uc.c:231 vs :233 (free-before-quiesce), intel_guc_ct.c:898 vs :902 (free-before-handler-swap), intel_guc_ct.c:214-218 (release map), intel_guc_ct.c:628/:838 (writes through desc), i915_irq.c:555-567 (disable+synchronize). fix.diff (2 files) applies clean via git apply --check.", "kernel_refs": [ "sys/dev/drm/i915/intel_uc.c:226", "sys/dev/drm/i915/intel_uc.c:231", "sys/dev/drm/i915/intel_uc.c:233", "sys/dev/drm/i915/intel_guc_ct.c:887", "sys/dev/drm/i915/intel_guc_ct.c:898", "sys/dev/drm/i915/intel_guc_ct.c:902", "sys/dev/drm/i915/intel_guc_ct.c:214", "sys/dev/drm/i915/intel_guc_ct.c:815", "sys/dev/drm/i915/intel_guc_ct.c:628", "sys/dev/drm/i915/intel_guc_ct.c:838", "sys/dev/drm/i915/i915_irq.c:555" ], "poc_changes": "none \u2014 no PoC source exists; teardown race on a path unreachable on this tree (no platform sets has_guc_ct; enable_guc default 0) and not attacker-timed even where reachable.", "attempts": 0, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 0, "guest_dirty": 0, "build_cmd": "", "run_cmd": "", "code_hash": "", "notes": "Info-tier lifetime hardening; upstream i915 later quiesced interrupts and switched the handler before freeing CT buffers. Guest has no Intel GPU; guest stays untouched (guest_dirty=0).", "recommended_fix": "In guc_disable_communication() call gen9_disable_guc_interrupts() and switch guc->send/guc->handler to nop BEFORE intel_guc_ct_disable(); inside intel_guc_ct_disable() swap send/handler before ctch_close() (see fix.diff).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "not_testable: the racing path is unreachable on this tree (no has_guc_ct platform, enable_guc default 0) and the guest has no Intel GPU, so neither baseline nor patched behavior can be exercised; the diff is line-accurate and git apply --check passes against the read-only sys/ tree.", "fix_evidence": "findings/poc/DF-4568/fix.diff (git apply --check clean); VERDICT.md section fix.diff." } |