Commit 12f15d52 authored by Tvrtko Ursulin's avatar Tvrtko Ursulin Committed by Tvrtko Ursulin
Browse files

drm: Do not allow userspace to trigger kernel warnings in drm_gem_change_handle_ioctl()



Since GEM bo handles are u32 in the uapi and the internal implementation
uses idr_alloc() which uses int ranges, passing a new handle larger than
INT_MAX trivially triggers a kernel warning:

idr_alloc():
...
	if (WARN_ON_ONCE(start < 0))
		return -EINVAL;
...

Fix it by rejecting new handles above INT_MAX and at the same time make
the end limit calculation more obvious by moving into int domain.

Signed-off-by: default avatarTvrtko Ursulin <tvrtko.ursulin@igalia.com>
Reported-by: default avatarZhi Wang <wangzhi@stu.xidian.edu.cn>
Fixes: 53096728 ("drm: Add DRM prime interface to reassign GEM handle")
Cc: David Francis <David.Francis@amd.com>
Cc: Felix Kuehling <felix.kuehling@amd.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: <stable@vger.kernel.org> # v6.18+
Tested-by: default avatarHarshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
Reviewed-by: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarTvrtko Ursulin <tursulin@ursulin.net>
Link: https://lore.kernel.org/r/20260123141540.76540-1-tvrtko.ursulin@igalia.com
parent 0a095b64
Loading
Loading
Loading
Loading
+12 −6
Original line number Diff line number Diff line
@@ -960,16 +960,21 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
{
	struct drm_gem_change_handle *args = data;
	struct drm_gem_object *obj;
	int ret;
	int handle, ret;

	if (!drm_core_check_feature(dev, DRIVER_GEM))
		return -EOPNOTSUPP;

	/* idr_alloc() limitation. */
	if (args->new_handle > INT_MAX)
		return -EINVAL;
	handle = args->new_handle;

	obj = drm_gem_object_lookup(file_priv, args->handle);
	if (!obj)
		return -ENOENT;

	if (args->handle == args->new_handle) {
	if (args->handle == handle) {
		ret = 0;
		goto out;
	}
@@ -977,18 +982,19 @@ int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data,
	mutex_lock(&file_priv->prime.lock);

	spin_lock(&file_priv->table_lock);
	ret = idr_alloc(&file_priv->object_idr, obj,
		args->new_handle, args->new_handle + 1, GFP_NOWAIT);
	ret = idr_alloc(&file_priv->object_idr, obj, handle, handle + 1,
			GFP_NOWAIT);
	spin_unlock(&file_priv->table_lock);

	if (ret < 0)
		goto out_unlock;

	if (obj->dma_buf) {
		ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf, args->new_handle);
		ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf,
					       handle);
		if (ret < 0) {
			spin_lock(&file_priv->table_lock);
			idr_remove(&file_priv->object_idr, args->new_handle);
			idr_remove(&file_priv->object_idr, handle);
			spin_unlock(&file_priv->table_lock);
			goto out_unlock;
		}