AMD General

since the new bo && guard already ensures bo is non-NULL (and equals 
bo_va->base.bo),
use bo directly instead of bo_va->base.bo - e.g. 
drm_gem_is_imported(&bo->tbo.base).


Regards,
Bob

-----Original Message-----
From: amd-gfx <[email protected]> On Behalf Of Jesse Zhang
Sent: Tuesday, July 28, 2026 9:46 AM
To: [email protected]
Cc: Deucher, Alexander <[email protected]>; Koenig, Christian 
<[email protected]>; Zhang, Jesse(Jie) <[email protected]>
Subject: [PATCH] drm/amdgpu: fix NULL pointer deref in amdgpu_vm_handle_moved 
for BO-less mappings

The individual.needs_update loop in amdgpu_vm_handle_moved() unconditionally 
dereferenced bo_va->base.bo (to read its reservation object, ttm_tt and to test 
for a DMABuf import). However bo_va->base.bo can legitimately be NULL for 
PRT/sparse mappings - amdgpu_vm_bo_update() already handles a NULL bo via its 
"else if (!bo)" PRT path. When such a bo_va reaches the moved list (e.g. the 
userq eviction restore worker running amdgpu_vm_handle_moved() while a user 
queue is being torn down during a GPU reset), the NULL deref crashes the kernel:

  BUG: kernel NULL pointer dereference, address: 0000000000000158
  #PF: supervisor read access in kernel mode
  Oops: 0000 [#1] SMP NOPTI
  Workqueue: events amdgpu_userq_restore_worker [amdgpu]
  RIP: 0010:amdgpu_vm_handle_moved+0x17a/0x200 [amdgpu]
  Call Trace:
   <TASK>
   amdgpu_userq_vm_validate_and_restore_queue+0x2ce/0x920 [amdgpu]
   amdgpu_userq_restore_worker+0xce/0x210 [amdgpu]
   process_scheduled_works+0xa6/0x460
   worker_thread+0x13c/0x290
   kthread+0xfb/0x140
   ret_from_fork+0x1b6/0x2b0
   ret_from_fork_asm+0x1a/0x30
   </TASK>

The faulting instruction is "mov rax,[rdx+0x158]" with rdx (bo) == 0 and
CR2 == 0x158, i.e. reading bo->tbo.base.resv off a NULL bo.

Guard the BO-less case: skip the reservation dance and the DMABuf-import check 
when bo is NULL, and let amdgpu_vm_bo_update() take its existing PRT path.

Signed-off-by: Jesse Zhang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index aac8ace9d7a6..fbb76c32bff9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -1631,11 +1631,17 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
                bo_va = list_first_entry(&vm->individual.needs_update,
                                         typeof(*bo_va), base.vm_status);
                bo = bo_va->base.bo;
-               resv = bo->tbo.base.resv;
+               resv = bo ? bo->tbo.base.resv : NULL;
                spin_unlock(&vm->individual_lock);

+               /* PRT/sparse mappings have no BO to reserve; just update the
+                * page tables (amdgpu_vm_bo_update() handles a NULL bo).
+                */
+               if (!bo) {
+                       clear = false;
+                       unlock = false;
                /* Try to reserve the BO to avoid clearing its ptes */
-               if (!adev->debug_vm && !amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) &&
+               } else if (!adev->debug_vm && 
!amdgpu_ttm_tt_get_usermm(bo->tbo.ttm)
+&&
                    dma_resv_trylock(resv)) {
                        clear = false;
                        unlock = true;
@@ -1659,7 +1665,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
                /* Remember evicted DMABuf imports in compute VMs for later
                 * validation
                 */
-               if (vm->is_compute_context &&
+               if (bo && vm->is_compute_context &&
                    drm_gem_is_imported(&bo_va->base.bo->tbo.base) &&
                    (!bo_va->base.bo->tbo.resource ||
                     bo_va->base.bo->tbo.resource->mem_type == TTM_PL_SYSTEM))
--
2.49.0

Reply via email to