⬢ DragonFlyBSD Kernel Audit
DF-4927 / fix.diff
← back to finding ↓ download raw
Port of upstream Linux commit 0381ac3ca2e7 ("drm/radeon: Initialize fences
array entries in radeon_sa_bo_next_hole", Xiaohui Zhang 2022, amdgpu twin
6a15f3ff19a8) to DragonFly's sys/dev/drm/radeon/radeon_sa.c.

Without the per-scan `fences[i] = NULL` initialization, a fence pointer
borrowed (uncounted) by one radeon_sa_bo_next_hole() call can be freed by
a later radeon_sa_bo_try_free()/next_hole() call on the same thread once
the GPU signals it, leaving a dangling pointer that radeon_sa_bo_new()
then feeds to radeon_fence_ref() (UAF write), radeon_fence_wait_any()
(UAF read) and radeon_fence_unref() (double free).

Validated on the line-faithful userspace port in this evidence pack:
baseline reproduces the UAF/double-free sequence deterministically,
--- a/sys/dev/drm/radeon/radeon_sa.c
+++ b/sys/dev/drm/radeon/radeon_sa.c
@@ -267,6 +267,8 @@
 	for (i = 0; i < RADEON_NUM_RINGS; ++i) {
 		struct radeon_sa_bo *sa_bo;
 
+		fences[i] = NULL;
+
 		if (list_empty(&sa_manager->flist[i])) {
 			continue;
 		}
@@ -332,10 +334,8 @@
 
 	lockmgr(&sa_manager->wq.lock, LK_EXCLUSIVE);
 	do {
-		for (i = 0; i < RADEON_NUM_RINGS; ++i) {
-			fences[i] = NULL;
+		for (i = 0; i < RADEON_NUM_RINGS; ++i)
 			tries[i] = 0;
-		}
 
 		do {
 			radeon_sa_bo_try_free(sa_manager);