From: Xiaogang Chen <[email protected]>

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 <[email protected]>
---
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 46 +++++++-----------------
 1 file changed, 12 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c 
b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index fc75d0009a57..bb4581f84f12 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -1282,18 +1282,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));
@@ -1374,7 +1367,6 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
 map_memory_to_gpu_failed:
 sync_memory_failed:
        mutex_unlock(&p->mutex);
-copy_from_user_failed:
        kfree(devices_arr);
 
        return err;
@@ -1399,18 +1391,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));
@@ -1476,7 +1461,6 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file 
*filep,
 unmap_memory_from_gpu_failed:
 sync_memory_failed:
        mutex_unlock(&p->mutex);
-copy_from_user_failed:
        kfree(devices_arr);
        return err;
 }
@@ -2336,17 +2320,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_array(args->num_devices, 
sizeof(*device_buckets), GFP_KERNEL);
-       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;
-- 
2.34.1

Reply via email to