⬢ DragonFlyBSD Kernel Audit
DF-4412 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/radeon/radeon_vm.c b/sys/dev/drm/radeon/radeon_vm.c
--- a/sys/dev/drm/radeon/radeon_vm.c
+++ b/sys/dev/drm/radeon/radeon_vm.c
@@ -130,13 +130,16 @@ struct radeon_bo_list *radeon_vm_get_bos(struct radeon_device *rdev,
 					  struct list_head *head)
 {
 	struct radeon_bo_list *list;
+	unsigned max_pde;
 	unsigned i, idx;
 
-	list = kvmalloc_array(vm->max_pde_used + 2,
+	/*
+	 * Snapshot the bound: vm->max_pde_used is grow-only and updated
+	 * under vm->mutex, which we may NOT hold here (both call sites run
+	 * before vm->mutex is taken).  Re-reading it live in the loop below
+	 * races a concurrent GEM_VA and overflows the array.
+	 */
+	max_pde = vm->max_pde_used;
+	list = kvmalloc_array(max_pde + 2,
 			     sizeof(struct radeon_bo_list), GFP_KERNEL);
 	if (!list)
 		return NULL;
@@ -146,7 +149,7 @@ struct radeon_bo_list *radeon_vm_get_bos(struct radeon_device *rdev,
 	list_add(&list[0].tv.head, head);
 
 	/* add the vm page tables to the list */
-	for (i = 0, idx = 1; i <= vm->max_pde_used; i++) {
+	for (i = 0, idx = 1; i <= max_pde; i++) {
 		if (!vm->page_tables[i].bo)
 			continue;