DragonFlyBSD Kernel Audit
DF-1555 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/drm_atomic_uapi.c b/sys/dev/drm/drm_atomic_uapi.c
--- a/sys/dev/drm/drm_atomic_uapi.c
+++ b/sys/dev/drm/drm_atomic_uapi.c
@@ -1077,6 +1077,14 @@
 
 	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
 		s32 __user *fence_ptr;
+		/*
+		 * DF-1555: track whether the event below was allocated purely
+		 * for the out-fence path; the setup_out_fence() error path
+		 * needs this to free the event instead of leaking it (on
+		 * DragonFly sync_file_create is a stub returning NULL, so the
+		 * fence pointer is never attached).
+		 */
+		bool event_for_fence_only = false;
 
 		fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
 
@@ -1103,6 +1111,8 @@
 				crtc_state->event = NULL;
 				return ret;
 			}
+		} else if (crtc_state->event) {
+			event_for_fence_only = true;
 		}
 
 		if (fence_ptr) {
@@ -1126,6 +1136,17 @@
 			ret = setup_out_fence(&f[(*num_fences)++], fence);
 			if (ret) {
 				dma_fence_put(fence);
+				/*
+				 * DF-1555: setup_out_fence failed before
+				 * crtc_state->event->base.fence was set; if we
+				 * allocated the event only for the out-fence path
+				 * it has neither fence nor file_priv set and
+				 * complete_signaling() would skip freeing it.
+				 */
+				if (event_for_fence_only && crtc_state->event) {
+					drm_event_cancel_free(dev, &crtc_state->event->base);
+					crtc_state->event = NULL;
+				}
 				return ret;
 			}