DragonFlyBSD Kernel Audit
DF-1863 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/amd/amdgpu/amdgpu_ctx.c b/sys/dev/drm/amd/amdgpu/amdgpu_ctx.c
--- a/sys/dev/drm/amd/amdgpu/amdgpu_ctx.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_ctx.c
@@ -442,18 +442,25 @@
 			  struct dma_fence *fence, uint64_t* handle)
 {
 	struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity);
-	uint64_t seq = centity->sequence;
+	uint64_t seq;
 	struct dma_fence *other = NULL;
 	unsigned idx = 0;
 
+	dma_fence_get(fence);
+
+	/*
+	 * DF-1863: claim the slot atomically with the write.  Reading
+	 * centity->sequence / fences[idx] OUTSIDE the lock allowed two
+	 * concurrent CS ioctl callers to observe the same `other` fence and
+	 * both dma_fence_put() it, producing a double-free / UAF on the prior
+	 * slot's drm_sched_fence (and leaking the loser's just-stored fence).
+	 */
+	lockmgr(&ctx->ring_lock, LK_EXCLUSIVE);
+	seq = centity->sequence;
 	idx = seq & (amdgpu_sched_jobs - 1);
 	other = centity->fences[idx];
 	if (other)
 		BUG_ON(!dma_fence_is_signaled(other));
-
-	dma_fence_get(fence);
-
-	lockmgr(&ctx->ring_lock, LK_EXCLUSIVE);
 	centity->fences[idx] = fence;
 	centity->sequence++;
 	lockmgr(&ctx->ring_lock, LK_RELEASE);