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: 4ddf4ddfce ("accel/qaic: Ensure entry belongs to DBC in qaic_perf_stats_bo_ioctl()")
Signed-off-by: Shuvam Pandey <shuvampandey1@gmail.com>
Reviewed-by: Jeff Hugo <jeff.hugo@oss.qualcomm.com>
Signed-off-by: Jeff Hugo <jeff.hugo@oss.qualcomm.com>
Link: https://patch.msgid.link/6a115824.a0bed9bd.3c0137.9edf@mx.google.com
This commit is contained in:
Shuvam Pandey 2026-05-23 13:17:33 +05:45 committed by Jeff Hugo
parent c274d6aaa3
commit 1c50c57717

View File

@ -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)))