When xa_alloc() for the per-process userq_xa fails in
amdgpu_userq_create(), the queue is freed with kfree() but not removed
from the global userq_doorbell_xa. This leaves a dangling pointer that
gets dereferenced when the kernel iterates userq_doorbell_xa during
suspend, resume, or GPU reset via xa_for_each().

The same missing cleanup exists in the amdgpu_userq_map_helper() failure
path.

Fix both error paths by adding xa_erase_irq() to remove the queue from
userq_doorbell_xa before freeing it.

Fixes: f18719ef4bb7 ("drm/amdgpu: Convert amdgpu userqueue management from IDR 
to XArray")
Reported-by: Yuhao Jiang <[email protected]>
Cc: [email protected]
Signed-off-by: Junrui Luo <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 7c450350847d..60e1f7541a64 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -864,6 +864,7 @@ amdgpu_userq_create(struct drm_file *filp, union 
drm_amdgpu_userq *args)
                     XA_LIMIT(1, AMDGPU_MAX_USERQ_COUNT), GFP_KERNEL);
        if (r) {
                drm_file_err(uq_mgr->file, "Failed to allocate a queue id\n");
+               xa_erase_irq(&adev->userq_doorbell_xa, index);
                amdgpu_userq_fence_driver_free(queue);
                uq_funcs->mqd_destroy(queue);
                kfree(queue);
@@ -884,6 +885,7 @@ amdgpu_userq_create(struct drm_file *filp, union 
drm_amdgpu_userq *args)
                r = amdgpu_userq_map_helper(queue);
                if (r) {
                        drm_file_err(uq_mgr->file, "Failed to map Queue\n");
+                       xa_erase_irq(&adev->userq_doorbell_xa, index);
                        xa_erase(&uq_mgr->userq_xa, qid);
                        amdgpu_userq_fence_driver_free(queue);
                        uq_funcs->mqd_destroy(queue);

-- 
2.51.2

Reply via email to