]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm: Do not allow userspace to trigger kernel warnings in drm_gem_change_handle_ioctl()
authorTvrtko Ursulin <tvrtko.ursulin@igalia.com>
Fri, 23 Jan 2026 14:15:40 +0000 (14:15 +0000)
committerTvrtko Ursulin <tursulin@ursulin.net>
Mon, 26 Jan 2026 11:45:51 +0000 (11:45 +0000)
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: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Reported-by: Zhi Wang <wangzhi@stu.xidian.edu.cn>
Fixes: 53096728b891 ("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: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Tvrtko Ursulin <tursulin@ursulin.net>
Link: https://lore.kernel.org/r/20260123141540.76540-1-tvrtko.ursulin@igalia.com
drivers/gpu/drm/drm_gem.c

index e4df434273945edefd425d1bafb7b34624de9f36..25f68fed9b4823db92660d03248ebb83bcd14361 100644 (file)
@@ -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;
                }