drm/amdkfd: Use memdup_array_user to copy data from/to user space at kfd ioctls

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)
This commit is contained in:
Xiaogang Chen
2026-06-16 13:25:56 -05:00
committed by Alex Deucher
parent 516bf737a5
commit 2321831d7e

View 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 @@ 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;
@@ -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 @@ 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;
}
@@ -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;