DF-4412 / fix.diff
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; |