]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amdkfd: Use memdup_array_user to copy data from/to user space at kfd ioctls
authorXiaogang Chen <xiaogang.chen@amd.com>
Tue, 16 Jun 2026 18:25:56 +0000 (13:25 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 17 Jun 2026 22:24:53 +0000 (18:24 -0400)
Several kfd ioctls need transfer array data from/to user space. Kfd driver
uses kmalloc_array with user provided size. That can oversize alloc or 32-bit
wrap with hostile value. Replace it by memdup_array_user that does overflow
checking and allocates through dedicated slab caches, also physical continuous
as kmalloc.

Signed-off-by: Xiaogang Chen <xiaogang.chen@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 4eca4742eb215951f9739ffe0122d179d545a7a4)

drivers/gpu/drm/amd/amdkfd/kfd_chardev.c

index 6a991ffa53fc122e47783a0ed46d405d83f9b06f..531e20748198c9e850b0ea1cf140d021323921fc 100644 (file)
@@ -1299,18 +1299,11 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
                return -EINVAL;
        }
 
-       devices_arr = kmalloc_array(args->n_devices, sizeof(*devices_arr),
-                                   GFP_KERNEL);
-       if (!devices_arr)
-               return -ENOMEM;
+       devices_arr = memdup_array_user((void *)args->device_ids_array_ptr,
+                                      args->n_devices, sizeof(*devices_arr));
 
-       err = copy_from_user(devices_arr,
-                            (void __user *)args->device_ids_array_ptr,
-                            args->n_devices * sizeof(*devices_arr));
-       if (err != 0) {
-               err = -EFAULT;
-               goto copy_from_user_failed;
-       }
+       if (IS_ERR(devices_arr))
+               return PTR_ERR(devices_arr);
 
        mutex_lock(&p->mutex);
        pdd = kfd_process_device_data_by_id(p, GET_GPU_ID(args->handle));
@@ -1391,7 +1384,6 @@ get_mem_obj_from_handle_failed:
 map_memory_to_gpu_failed:
 sync_memory_failed:
        mutex_unlock(&p->mutex);
-copy_from_user_failed:
        kfree(devices_arr);
 
        return err;
@@ -1416,18 +1408,11 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep,
                return -EINVAL;
        }
 
-       devices_arr = kmalloc_array(args->n_devices, sizeof(*devices_arr),
-                                   GFP_KERNEL);
-       if (!devices_arr)
-               return -ENOMEM;
+       devices_arr = memdup_array_user((void *)args->device_ids_array_ptr,
+                                      args->n_devices, sizeof(*devices_arr));
 
-       err = copy_from_user(devices_arr,
-                            (void __user *)args->device_ids_array_ptr,
-                            args->n_devices * sizeof(*devices_arr));
-       if (err != 0) {
-               err = -EFAULT;
-               goto copy_from_user_failed;
-       }
+       if (IS_ERR(devices_arr))
+               return PTR_ERR(devices_arr);
 
        mutex_lock(&p->mutex);
        pdd = kfd_process_device_data_by_id(p, GET_GPU_ID(args->handle));
@@ -1493,7 +1478,6 @@ get_mem_obj_from_handle_failed:
 unmap_memory_from_gpu_failed:
 sync_memory_failed:
        mutex_unlock(&p->mutex);
-copy_from_user_failed:
        kfree(devices_arr);
        return err;
 }
@@ -2353,17 +2337,11 @@ static int criu_restore_devices(struct kfd_process *p,
        if (*priv_offset + (args->num_devices * sizeof(*device_privs)) > max_priv_data_size)
                return -EINVAL;
 
-       device_buckets = kmalloc_objs(*device_buckets, args->num_devices);
-       if (!device_buckets)
-               return -ENOMEM;
+       device_buckets = memdup_array_user((void *)args->devices,
+                                       args->num_devices, sizeof(*device_buckets));
 
-       ret = copy_from_user(device_buckets, (void __user *)args->devices,
-                               args->num_devices * sizeof(*device_buckets));
-       if (ret) {
-               pr_err("Failed to copy devices buckets from user\n");
-               ret = -EFAULT;
-               goto exit;
-       }
+       if (IS_ERR(device_buckets))
+               return PTR_ERR(device_buckets);
 
        for (i = 0; i < args->num_devices; i++) {
                struct kfd_node *dev;