⬢ DragonFlyBSD Kernel Audit
DF-4314 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/i915/intel_overlay.c	2026-09-19 09:33:41.608721811 +0000
+++ b/sys/dev/drm/i915/intel_overlay.c	2026-09-19 09:33:52.932577054 +0000
@@ -370,8 +370,15 @@
 
 	intel_overlay_release_old_vma(overlay);
 
-	overlay->crtc->overlay = NULL;
-	overlay->crtc = NULL;
+	/*
+	 * A GPU reset may have run intel_overlay_reset() while our off
+	 * request was still in flight; that clears overlay->crtc (and
+	 * releases old_vma).  Do not dereference a cleared crtc here.
+	 */
+	if (overlay->crtc) {
+		overlay->crtc->overlay = NULL;
+		overlay->crtc = NULL;
+	}
 	overlay->active = false;
 
 	if (IS_I830(dev_priv))
@@ -481,6 +488,21 @@
 	if (!overlay)
 		return;
 
+	/*
+	 * Retire any still-pending flip first (e.g. the retire callback of
+	 * an in-flight intel_overlay_off()) BEFORE clearing the overlay
+	 * state.  Otherwise:
+	 *   (a) intel_overlay_off_tail() fires later, after overlay->crtc
+	 *       has been NULLed here, and dereferences it (NULL+offset
+	 *       write => kernel page fault); or
+	 *   (b) intel_overlay_release_old_vid() below submits a new wait
+	 *       while last_flip still tracks the un-retired off request,
+	 *       tripping GEM_BUG_ON() in intel_overlay_submit_request().
+	 * After a GPU reset the request is already complete, so retiring
+	 * here is instantaneous and runs the callback with crtc valid.
+	 */
+	intel_overlay_recover_from_interrupt(overlay);
+
 	intel_overlay_release_old_vid(overlay);
 
 	overlay->old_xscale = 0;