Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

vfio: Adapt drivers to use the core helper vfio_check_precopy_ioctl

Introduce a core helper function for VFIO_MIG_GET_PRECOPY_INFO and adapt
all drivers to use it.

It centralizes the common code and ensures that output flags are cleared
on entry, in case user opts in to VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2.
This preventing any unintended echoing of userspace data back to
userspace.

Signed-off-by: Yishai Hadas <yishaih@nvidia.com>
Link: https://lore.kernel.org/r/20260317161753.18964-4-yishaih@nvidia.com
Signed-off-by: Alex Williamson <alex@shazbot.org>

authored by

Yishai Hadas and committed by
Alex Williamson
c9954986 50ff3f40

+68 -56
+6 -11
drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
··· 857 857 struct hisi_acc_vf_core_device *hisi_acc_vdev = migf->hisi_acc_vdev; 858 858 loff_t *pos = &filp->f_pos; 859 859 struct vfio_precopy_info info; 860 - unsigned long minsz; 861 860 int ret; 862 861 863 - if (cmd != VFIO_MIG_GET_PRECOPY_INFO) 864 - return -ENOTTY; 865 - 866 - minsz = offsetofend(struct vfio_precopy_info, dirty_bytes); 867 - 868 - if (copy_from_user(&info, (void __user *)arg, minsz)) 869 - return -EFAULT; 870 - if (info.argsz < minsz) 871 - return -EINVAL; 862 + ret = vfio_check_precopy_ioctl(&hisi_acc_vdev->core_device.vdev, cmd, 863 + arg, &info); 864 + if (ret) 865 + return ret; 872 866 873 867 mutex_lock(&hisi_acc_vdev->state_mutex); 874 868 if (hisi_acc_vdev->mig_state != VFIO_DEVICE_STATE_PRE_COPY) { ··· 887 893 mutex_unlock(&migf->lock); 888 894 mutex_unlock(&hisi_acc_vdev->state_mutex); 889 895 890 - return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0; 896 + return copy_to_user((void __user *)arg, &info, 897 + offsetofend(struct vfio_precopy_info, dirty_bytes)) ? -EFAULT : 0; 891 898 out: 892 899 mutex_unlock(&migf->lock); 893 900 mutex_unlock(&hisi_acc_vdev->state_mutex);
+6 -12
drivers/vfio/pci/mlx5/main.c
··· 463 463 struct mlx5_vhca_data_buffer *buf; 464 464 struct vfio_precopy_info info = {}; 465 465 loff_t *pos = &filp->f_pos; 466 - unsigned long minsz; 467 466 size_t inc_length = 0; 468 467 bool end_of_data = false; 469 468 int ret; 470 469 471 - if (cmd != VFIO_MIG_GET_PRECOPY_INFO) 472 - return -ENOTTY; 473 - 474 - minsz = offsetofend(struct vfio_precopy_info, dirty_bytes); 475 - 476 - if (copy_from_user(&info, (void __user *)arg, minsz)) 477 - return -EFAULT; 478 - 479 - if (info.argsz < minsz) 480 - return -EINVAL; 470 + ret = vfio_check_precopy_ioctl(&mvdev->core_device.vdev, cmd, arg, 471 + &info); 472 + if (ret) 473 + return ret; 481 474 482 475 mutex_lock(&mvdev->state_mutex); 483 476 if (mvdev->mig_state != VFIO_DEVICE_STATE_PRE_COPY && ··· 538 545 539 546 done: 540 547 mlx5vf_state_mutex_unlock(mvdev); 541 - if (copy_to_user((void __user *)arg, &info, minsz)) 548 + if (copy_to_user((void __user *)arg, &info, 549 + offsetofend(struct vfio_precopy_info, dirty_bytes))) 542 550 return -EFAULT; 543 551 return 0; 544 552
+6 -11
drivers/vfio/pci/qat/main.c
··· 121 121 struct qat_mig_dev *mig_dev = qat_vdev->mdev; 122 122 struct vfio_precopy_info info; 123 123 loff_t *pos = &filp->f_pos; 124 - unsigned long minsz; 125 124 int ret = 0; 126 125 127 - if (cmd != VFIO_MIG_GET_PRECOPY_INFO) 128 - return -ENOTTY; 129 - 130 - minsz = offsetofend(struct vfio_precopy_info, dirty_bytes); 131 - 132 - if (copy_from_user(&info, (void __user *)arg, minsz)) 133 - return -EFAULT; 134 - if (info.argsz < minsz) 135 - return -EINVAL; 126 + ret = vfio_check_precopy_ioctl(&qat_vdev->core_device.vdev, cmd, arg, 127 + &info); 128 + if (ret) 129 + return ret; 136 130 137 131 mutex_lock(&qat_vdev->state_mutex); 138 132 if (qat_vdev->mig_state != VFIO_DEVICE_STATE_PRE_COPY && ··· 154 160 mutex_unlock(&qat_vdev->state_mutex); 155 161 if (ret) 156 162 return ret; 157 - return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0; 163 + return copy_to_user((void __user *)arg, &info, 164 + offsetofend(struct vfio_precopy_info, dirty_bytes)) ? -EFAULT : 0; 158 165 } 159 166 160 167 static ssize_t qat_vf_save_read(struct file *filp, char __user *buf,
+6 -11
drivers/vfio/pci/virtio/migrate.c
··· 443 443 struct vfio_precopy_info info = {}; 444 444 loff_t *pos = &filp->f_pos; 445 445 bool end_of_data = false; 446 - unsigned long minsz; 447 446 u32 ctx_size = 0; 448 447 int ret; 449 448 450 - if (cmd != VFIO_MIG_GET_PRECOPY_INFO) 451 - return -ENOTTY; 452 - 453 - minsz = offsetofend(struct vfio_precopy_info, dirty_bytes); 454 - if (copy_from_user(&info, (void __user *)arg, minsz)) 455 - return -EFAULT; 456 - 457 - if (info.argsz < minsz) 458 - return -EINVAL; 449 + ret = vfio_check_precopy_ioctl(&virtvdev->core_device.vdev, cmd, arg, 450 + &info); 451 + if (ret) 452 + return ret; 459 453 460 454 mutex_lock(&virtvdev->state_mutex); 461 455 if (virtvdev->mig_state != VFIO_DEVICE_STATE_PRE_COPY && ··· 508 514 509 515 done: 510 516 virtiovf_state_mutex_unlock(virtvdev); 511 - if (copy_to_user((void __user *)arg, &info, minsz)) 517 + if (copy_to_user((void __user *)arg, &info, 518 + offsetofend(struct vfio_precopy_info, dirty_bytes))) 512 519 return -EFAULT; 513 520 return 0; 514 521
+39
include/linux/vfio.h
··· 16 16 #include <linux/cdev.h> 17 17 #include <uapi/linux/vfio.h> 18 18 #include <linux/iova_bitmap.h> 19 + #include <linux/uaccess.h> 19 20 20 21 struct kvm; 21 22 struct iommufd_ctx; ··· 284 283 if (argsz < minsz) 285 284 return -EINVAL; 286 285 return 1; 286 + } 287 + 288 + /** 289 + * vfio_check_precopy_ioctl - Validate user input for the VFIO_MIG_GET_PRECOPY_INFO ioctl 290 + * @vdev: The vfio device 291 + * @cmd: Cmd from the ioctl 292 + * @arg: Arg from the ioctl 293 + * @info: Driver pointer to hold the userspace input to the ioctl 294 + * 295 + * For use in a driver's get_precopy_info. Checks that the inputs to the 296 + * VFIO_MIG_GET_PRECOPY_INFO ioctl are correct. 297 + 298 + * Returns 0 on success, otherwise errno. 299 + */ 300 + 301 + static inline int 302 + vfio_check_precopy_ioctl(struct vfio_device *vdev, unsigned int cmd, 303 + unsigned long arg, struct vfio_precopy_info *info) 304 + { 305 + unsigned long minsz; 306 + 307 + if (cmd != VFIO_MIG_GET_PRECOPY_INFO) 308 + return -ENOTTY; 309 + 310 + minsz = offsetofend(struct vfio_precopy_info, dirty_bytes); 311 + 312 + if (copy_from_user(info, (void __user *)arg, minsz)) 313 + return -EFAULT; 314 + 315 + if (info->argsz < minsz) 316 + return -EINVAL; 317 + 318 + /* keep v1 behaviour as is for compatibility reasons */ 319 + if (vdev->precopy_info_v2) 320 + /* flags are output, set its initial value to 0 */ 321 + info->flags = 0; 322 + 323 + return 0; 287 324 } 288 325 289 326 struct vfio_device *_vfio_alloc_device(size_t size, struct device *dev,
+5 -11
samples/vfio-mdev/mtty.c
··· 840 840 struct mdev_state *mdev_state = migf->mdev_state; 841 841 loff_t *pos = &filp->f_pos; 842 842 struct vfio_precopy_info info = {}; 843 - unsigned long minsz; 844 843 int ret; 845 844 846 - if (cmd != VFIO_MIG_GET_PRECOPY_INFO) 847 - return -ENOTTY; 848 - 849 - minsz = offsetofend(struct vfio_precopy_info, dirty_bytes); 850 - 851 - if (copy_from_user(&info, (void __user *)arg, minsz)) 852 - return -EFAULT; 853 - if (info.argsz < minsz) 854 - return -EINVAL; 845 + ret = vfio_check_precopy_ioctl(&mdev_state->vdev, cmd, arg, &info); 846 + if (ret) 847 + return ret; 855 848 856 849 mutex_lock(&mdev_state->state_mutex); 857 850 if (mdev_state->state != VFIO_DEVICE_STATE_PRE_COPY && ··· 871 878 info.initial_bytes = migf->filled_size - *pos; 872 879 mutex_unlock(&migf->lock); 873 880 874 - ret = copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0; 881 + ret = copy_to_user((void __user *)arg, &info, 882 + offsetofend(struct vfio_precopy_info, dirty_bytes)) ? -EFAULT : 0; 875 883 unlock: 876 884 mtty_state_mutex_unlock(mdev_state); 877 885 return ret;