From 1c50c57717c013ca63363eecb4154049cc727767 Mon Sep 17 00:00:00 2001 From: Shuvam Pandey Date: Sat, 23 May 2026 13:17:33 +0545 Subject: [PATCH] accel/qaic: Protect perf stats BO state with bo->lock qaic_perf_stats_bo_ioctl() validates each BO by checking bo->sliced and bo->dbc before returning its perf stats. These fields are changed by the detach paths while holding bo->lock, but the perf stats ioctl reads them without that lock. A concurrent detach can clear bo->dbc and mark the BO unsliced while the perf stats ioctl is validating the BO. Take bo->lock while checking the BO state and copying the per-BO stats into the temporary result buffer. Fixes: 4ddf4ddfceb4 ("accel/qaic: Ensure entry belongs to DBC in qaic_perf_stats_bo_ioctl()") Signed-off-by: Shuvam Pandey Reviewed-by: Jeff Hugo Signed-off-by: Jeff Hugo Link: https://patch.msgid.link/6a115824.a0bed9bd.3c0137.9edf@mx.google.com --- drivers/accel/qaic/qaic_data.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 4d55531bf1c9..ee35e13091b3 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -1840,15 +1840,16 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file goto free_ent; } bo = to_qaic_bo(obj); + ret = mutex_lock_interruptible(&bo->lock); + if (ret) + goto put_obj; if (!bo->sliced) { - drm_gem_object_put(obj); ret = -EINVAL; - goto free_ent; + goto unlock_bo; } if (bo->dbc->id != args->hdr.dbc_id) { - drm_gem_object_put(obj); ret = -EINVAL; - goto free_ent; + goto unlock_bo; } /* * perf stats ioctl is called before wait ioctl is complete then @@ -1864,7 +1865,12 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file bo->perf_stats.req_received_ts), 1000); ent[i].queue_level_before = bo->perf_stats.queue_level_before; ent[i].num_queue_element = bo->total_slice_nents; +unlock_bo: + mutex_unlock(&bo->lock); +put_obj: drm_gem_object_put(obj); + if (ret) + goto free_ent; } if (copy_to_user(u64_to_user_ptr(args->data), ent, args->hdr.count * sizeof(*ent)))