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

vfio/pci: Do vf_token checks for VFIO_DEVICE_BIND_IOMMUFD

This was missed during the initial implementation. The VFIO PCI encodes
the vf_token inside the device name when opening the device from the group
FD, something like:

"0000:04:10.0 vf_token=bd8d9d2b-5a5f-4f5a-a211-f591514ba1f3"

This is used to control access to a VF unless there is co-ordination with
the owner of the PF.

Since we no longer have a device name in the cdev path, pass the token
directly through VFIO_DEVICE_BIND_IOMMUFD using an optional field
indicated by VFIO_DEVICE_BIND_FLAG_TOKEN.

Fixes: 5fcc26969a16 ("vfio: Add VFIO_DEVICE_BIND_IOMMUFD")
Tested-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Reviewed-by: Yi Liu <yi.l.liu@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/0-v3-bdd8716e85fe+3978a-vfio_token_jgg@nvidia.com
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>

authored by

Jason Gunthorpe and committed by
Alex Williamson
86624ba3 b3060198

+76 -12
+35 -3
drivers/vfio/device_cdev.c
··· 60 60 spin_unlock(&df->kvm_ref_lock); 61 61 } 62 62 63 + static int vfio_df_check_token(struct vfio_device *device, 64 + const struct vfio_device_bind_iommufd *bind) 65 + { 66 + uuid_t uuid; 67 + 68 + if (!device->ops->match_token_uuid) { 69 + if (bind->flags & VFIO_DEVICE_BIND_FLAG_TOKEN) 70 + return -EINVAL; 71 + return 0; 72 + } 73 + 74 + if (!(bind->flags & VFIO_DEVICE_BIND_FLAG_TOKEN)) 75 + return device->ops->match_token_uuid(device, NULL); 76 + 77 + if (copy_from_user(&uuid, u64_to_user_ptr(bind->token_uuid_ptr), 78 + sizeof(uuid))) 79 + return -EFAULT; 80 + return device->ops->match_token_uuid(device, &uuid); 81 + } 82 + 63 83 long vfio_df_ioctl_bind_iommufd(struct vfio_device_file *df, 64 84 struct vfio_device_bind_iommufd __user *arg) 65 85 { 86 + const u32 VALID_FLAGS = VFIO_DEVICE_BIND_FLAG_TOKEN; 66 87 struct vfio_device *device = df->device; 67 88 struct vfio_device_bind_iommufd bind; 68 89 unsigned long minsz; 90 + u32 user_size; 69 91 int ret; 70 92 71 93 static_assert(__same_type(arg->out_devid, df->devid)); 72 94 73 95 minsz = offsetofend(struct vfio_device_bind_iommufd, out_devid); 74 96 75 - if (copy_from_user(&bind, arg, minsz)) 76 - return -EFAULT; 97 + ret = get_user(user_size, &arg->argsz); 98 + if (ret) 99 + return ret; 100 + if (user_size < minsz) 101 + return -EINVAL; 102 + ret = copy_struct_from_user(&bind, minsz, arg, user_size); 103 + if (ret) 104 + return ret; 77 105 78 - if (bind.argsz < minsz || bind.flags || bind.iommufd < 0) 106 + if (bind.iommufd < 0 || bind.flags & ~VALID_FLAGS) 79 107 return -EINVAL; 80 108 81 109 /* BIND_IOMMUFD only allowed for cdev fds */ ··· 120 92 ret = -EINVAL; 121 93 goto out_unlock; 122 94 } 95 + 96 + ret = vfio_df_check_token(device, &bind); 97 + if (ret) 98 + goto out_unlock; 123 99 124 100 df->iommufd = iommufd_ctx_from_fd(bind.iommufd); 125 101 if (IS_ERR(df->iommufd)) {
+1
drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
··· 1583 1583 .mmap = vfio_pci_core_mmap, 1584 1584 .request = vfio_pci_core_request, 1585 1585 .match = vfio_pci_core_match, 1586 + .match_token_uuid = vfio_pci_core_match_token_uuid, 1586 1587 .bind_iommufd = vfio_iommufd_physical_bind, 1587 1588 .unbind_iommufd = vfio_iommufd_physical_unbind, 1588 1589 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+1
drivers/vfio/pci/mlx5/main.c
··· 1372 1372 .mmap = vfio_pci_core_mmap, 1373 1373 .request = vfio_pci_core_request, 1374 1374 .match = vfio_pci_core_match, 1375 + .match_token_uuid = vfio_pci_core_match_token_uuid, 1375 1376 .bind_iommufd = vfio_iommufd_physical_bind, 1376 1377 .unbind_iommufd = vfio_iommufd_physical_unbind, 1377 1378 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+2
drivers/vfio/pci/nvgrace-gpu/main.c
··· 696 696 .mmap = nvgrace_gpu_mmap, 697 697 .request = vfio_pci_core_request, 698 698 .match = vfio_pci_core_match, 699 + .match_token_uuid = vfio_pci_core_match_token_uuid, 699 700 .bind_iommufd = vfio_iommufd_physical_bind, 700 701 .unbind_iommufd = vfio_iommufd_physical_unbind, 701 702 .attach_ioas = vfio_iommufd_physical_attach_ioas, ··· 716 715 .mmap = vfio_pci_core_mmap, 717 716 .request = vfio_pci_core_request, 718 717 .match = vfio_pci_core_match, 718 + .match_token_uuid = vfio_pci_core_match_token_uuid, 719 719 .bind_iommufd = vfio_iommufd_physical_bind, 720 720 .unbind_iommufd = vfio_iommufd_physical_unbind, 721 721 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+1
drivers/vfio/pci/pds/vfio_dev.c
··· 201 201 .mmap = vfio_pci_core_mmap, 202 202 .request = vfio_pci_core_request, 203 203 .match = vfio_pci_core_match, 204 + .match_token_uuid = vfio_pci_core_match_token_uuid, 204 205 .bind_iommufd = vfio_iommufd_physical_bind, 205 206 .unbind_iommufd = vfio_iommufd_physical_unbind, 206 207 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+1
drivers/vfio/pci/qat/main.c
··· 614 614 .mmap = vfio_pci_core_mmap, 615 615 .request = vfio_pci_core_request, 616 616 .match = vfio_pci_core_match, 617 + .match_token_uuid = vfio_pci_core_match_token_uuid, 617 618 .bind_iommufd = vfio_iommufd_physical_bind, 618 619 .unbind_iommufd = vfio_iommufd_physical_unbind, 619 620 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+1
drivers/vfio/pci/vfio_pci.c
··· 138 138 .mmap = vfio_pci_core_mmap, 139 139 .request = vfio_pci_core_request, 140 140 .match = vfio_pci_core_match, 141 + .match_token_uuid = vfio_pci_core_match_token_uuid, 141 142 .bind_iommufd = vfio_iommufd_physical_bind, 142 143 .unbind_iommufd = vfio_iommufd_physical_unbind, 143 144 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+14 -8
drivers/vfio/pci/vfio_pci_core.c
··· 1821 1821 } 1822 1822 EXPORT_SYMBOL_GPL(vfio_pci_core_request); 1823 1823 1824 - static int vfio_pci_validate_vf_token(struct vfio_pci_core_device *vdev, 1825 - bool vf_token, uuid_t *uuid) 1824 + int vfio_pci_core_match_token_uuid(struct vfio_device *core_vdev, 1825 + const uuid_t *uuid) 1826 + 1826 1827 { 1828 + struct vfio_pci_core_device *vdev = 1829 + container_of(core_vdev, struct vfio_pci_core_device, vdev); 1830 + 1827 1831 /* 1828 1832 * There's always some degree of trust or collaboration between SR-IOV 1829 1833 * PF and VFs, even if just that the PF hosts the SR-IOV capability and ··· 1858 1854 bool match; 1859 1855 1860 1856 if (!pf_vdev) { 1861 - if (!vf_token) 1857 + if (!uuid) 1862 1858 return 0; /* PF is not vfio-pci, no VF token */ 1863 1859 1864 1860 pci_info_ratelimited(vdev->pdev, ··· 1866 1862 return -EINVAL; 1867 1863 } 1868 1864 1869 - if (!vf_token) { 1865 + if (!uuid) { 1870 1866 pci_info_ratelimited(vdev->pdev, 1871 1867 "VF token required to access device\n"); 1872 1868 return -EACCES; ··· 1884 1880 } else if (vdev->vf_token) { 1885 1881 mutex_lock(&vdev->vf_token->lock); 1886 1882 if (vdev->vf_token->users) { 1887 - if (!vf_token) { 1883 + if (!uuid) { 1888 1884 mutex_unlock(&vdev->vf_token->lock); 1889 1885 pci_info_ratelimited(vdev->pdev, 1890 1886 "VF token required to access device\n"); ··· 1897 1893 "Incorrect VF token provided for device\n"); 1898 1894 return -EACCES; 1899 1895 } 1900 - } else if (vf_token) { 1896 + } else if (uuid) { 1901 1897 uuid_copy(&vdev->vf_token->uuid, uuid); 1902 1898 } 1903 1899 1904 1900 mutex_unlock(&vdev->vf_token->lock); 1905 - } else if (vf_token) { 1901 + } else if (uuid) { 1906 1902 pci_info_ratelimited(vdev->pdev, 1907 1903 "VF token incorrectly provided, not a PF or VF\n"); 1908 1904 return -EINVAL; ··· 1910 1906 1911 1907 return 0; 1912 1908 } 1909 + EXPORT_SYMBOL_GPL(vfio_pci_core_match_token_uuid); 1913 1910 1914 1911 #define VF_TOKEN_ARG "vf_token=" 1915 1912 ··· 1957 1952 } 1958 1953 } 1959 1954 1960 - ret = vfio_pci_validate_vf_token(vdev, vf_token, &uuid); 1955 + ret = core_vdev->ops->match_token_uuid(core_vdev, 1956 + vf_token ? &uuid : NULL); 1961 1957 if (ret) 1962 1958 return ret; 1963 1959
+3
drivers/vfio/pci/virtio/main.c
··· 94 94 .mmap = vfio_pci_core_mmap, 95 95 .request = vfio_pci_core_request, 96 96 .match = vfio_pci_core_match, 97 + .match_token_uuid = vfio_pci_core_match_token_uuid, 97 98 .bind_iommufd = vfio_iommufd_physical_bind, 98 99 .unbind_iommufd = vfio_iommufd_physical_unbind, 99 100 .attach_ioas = vfio_iommufd_physical_attach_ioas, ··· 115 114 .mmap = vfio_pci_core_mmap, 116 115 .request = vfio_pci_core_request, 117 116 .match = vfio_pci_core_match, 117 + .match_token_uuid = vfio_pci_core_match_token_uuid, 118 118 .bind_iommufd = vfio_iommufd_physical_bind, 119 119 .unbind_iommufd = vfio_iommufd_physical_unbind, 120 120 .attach_ioas = vfio_iommufd_physical_attach_ioas, ··· 136 134 .mmap = vfio_pci_core_mmap, 137 135 .request = vfio_pci_core_request, 138 136 .match = vfio_pci_core_match, 137 + .match_token_uuid = vfio_pci_core_match_token_uuid, 139 138 .bind_iommufd = vfio_iommufd_physical_bind, 140 139 .unbind_iommufd = vfio_iommufd_physical_unbind, 141 140 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+4
include/linux/vfio.h
··· 105 105 * @match: Optional device name match callback (return: 0 for no-match, >0 for 106 106 * match, -errno for abort (ex. match with insufficient or incorrect 107 107 * additional args) 108 + * @match_token_uuid: Optional device token match/validation. Return 0 109 + * if the uuid is valid for the device, -errno otherwise. uuid is NULL 110 + * if none was provided. 108 111 * @dma_unmap: Called when userspace unmaps IOVA from the container 109 112 * this device is attached to. 110 113 * @device_feature: Optional, fill in the VFIO_DEVICE_FEATURE ioctl ··· 135 132 int (*mmap)(struct vfio_device *vdev, struct vm_area_struct *vma); 136 133 void (*request)(struct vfio_device *vdev, unsigned int count); 137 134 int (*match)(struct vfio_device *vdev, char *buf); 135 + int (*match_token_uuid)(struct vfio_device *vdev, const uuid_t *uuid); 138 136 void (*dma_unmap)(struct vfio_device *vdev, u64 iova, u64 length); 139 137 int (*device_feature)(struct vfio_device *device, u32 flags, 140 138 void __user *arg, size_t argsz);
+2
include/linux/vfio_pci_core.h
··· 122 122 int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma); 123 123 void vfio_pci_core_request(struct vfio_device *core_vdev, unsigned int count); 124 124 int vfio_pci_core_match(struct vfio_device *core_vdev, char *buf); 125 + int vfio_pci_core_match_token_uuid(struct vfio_device *core_vdev, 126 + const uuid_t *uuid); 125 127 int vfio_pci_core_enable(struct vfio_pci_core_device *vdev); 126 128 void vfio_pci_core_disable(struct vfio_pci_core_device *vdev); 127 129 void vfio_pci_core_finish_enable(struct vfio_pci_core_device *vdev);
+11 -1
include/uapi/linux/vfio.h
··· 905 905 * VFIO_DEVICE_BIND_IOMMUFD - _IOR(VFIO_TYPE, VFIO_BASE + 18, 906 906 * struct vfio_device_bind_iommufd) 907 907 * @argsz: User filled size of this data. 908 - * @flags: Must be 0. 908 + * @flags: Must be 0 or a bit flags of VFIO_DEVICE_BIND_* 909 909 * @iommufd: iommufd to bind. 910 910 * @out_devid: The device id generated by this bind. devid is a handle for 911 911 * this device/iommufd bond and can be used in IOMMUFD commands. 912 + * @token_uuid_ptr: Valid if VFIO_DEVICE_BIND_FLAG_TOKEN. Points to a 16 byte 913 + * UUID in the same format as VFIO_DEVICE_FEATURE_PCI_VF_TOKEN. 912 914 * 913 915 * Bind a vfio_device to the specified iommufd. 914 916 * ··· 919 917 * 920 918 * Unbind is automatically conducted when device fd is closed. 921 919 * 920 + * A token is sometimes required to open the device, unless this is known to be 921 + * needed VFIO_DEVICE_BIND_FLAG_TOKEN should not be set and token_uuid_ptr is 922 + * ignored. The only case today is a PF/VF relationship where the VF bind must 923 + * be provided the same token as VFIO_DEVICE_FEATURE_PCI_VF_TOKEN provided to 924 + * the PF. 925 + * 922 926 * Return: 0 on success, -errno on failure. 923 927 */ 924 928 struct vfio_device_bind_iommufd { 925 929 __u32 argsz; 926 930 __u32 flags; 931 + #define VFIO_DEVICE_BIND_FLAG_TOKEN (1 << 0) 927 932 __s32 iommufd; 928 933 __u32 out_devid; 934 + __aligned_u64 token_uuid_ptr; 929 935 }; 930 936 931 937 #define VFIO_DEVICE_BIND_IOMMUFD _IO(VFIO_TYPE, VFIO_BASE + 18)