GET_INFO accesses PCI configuration to report AtomicOps support, and GET_REGION_INFO maps the ROM to validate its contents. Protect these hardware accesses with access_srcu. Hold SRCU through DMA-BUF creation and list insertion so recovery cannot finish revoking buffers before a concurrent export becomes visible. Assisted-by: LLM Signed-off-by: Shameer Kolothum --- drivers/vfio/pci/vfio_pci_core.c | 13 ++++++++++++- drivers/vfio/pci/vfio_pci_dmabuf.c | 16 +++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index 38551bdedc89..92497224f471 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -1112,7 +1112,7 @@ static int vfio_pci_ioctl_get_info(struct vfio_pci_core_device *vdev, unsigned long minsz = offsetofend(struct vfio_device_info, num_irqs); struct vfio_device_info info = {}; struct vfio_info_cap caps = { .buf = NULL, .size = 0 }; - int ret; + int ret, idx; if (copy_from_user(&info, arg, minsz)) return -EFAULT; @@ -1137,7 +1137,13 @@ static int vfio_pci_ioctl_get_info(struct vfio_pci_core_device *vdev, return ret; } + idx = vfio_pci_core_access_begin(vdev); + if (idx < 0) { + kfree(caps.buf); + return idx; + } ret = vfio_pci_info_atomic_cap(vdev, &caps); + vfio_pci_core_access_end(vdev, idx); if (ret && ret != -ENODEV) { pci_warn(vdev->pdev, "Failed to setup AtomicOps info capability\n"); @@ -1213,6 +1219,10 @@ int vfio_pci_ioctl_get_region_info(struct vfio_device *core_vdev, * Check ROM content is valid. Need to enable memory * decode for ROM access in pci_map_rom(). */ + int idx = vfio_pci_core_access_begin(vdev); + + if (idx < 0) + return idx; cmd = vfio_pci_memory_lock_and_enable(vdev); io = pci_map_rom(pdev, &size); if (io) { @@ -1223,6 +1233,7 @@ int vfio_pci_ioctl_get_region_info(struct vfio_device *core_vdev, pci_unmap_rom(pdev, io); } vfio_pci_memory_unlock_and_restore(vdev, cmd); + vfio_pci_core_access_end(vdev, idx); } else if (pdev->rom && pdev->romlen) { info->flags = VFIO_REGION_INFO_FLAG_READ; /* Report BAR size as power of two. */ diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c index c16f460c01d6..c1a0250af680 100644 --- a/drivers/vfio/pci/vfio_pci_dmabuf.c +++ b/drivers/vfio/pci/vfio_pci_dmabuf.c @@ -227,7 +227,7 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags, DEFINE_DMA_BUF_EXPORT_INFO(exp_info); struct vfio_pci_dma_buf *priv; size_t length; - int ret; + int ret, idx; if (!vdev->pci_ops || !vdev->pci_ops->get_dmabuf_phys) return -EOPNOTSUPP; @@ -274,19 +274,26 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags, priv->vdev = vdev; priv->nr_ranges = get_dma_buf.nr_ranges; priv->size = length; + + idx = vfio_pci_core_access_begin(vdev); + if (idx < 0) { + ret = idx; + goto err_free_phys; + } + ret = vdev->pci_ops->get_dmabuf_phys(vdev, &priv->provider, get_dma_buf.region_index, priv->phys_vec, dma_ranges, priv->nr_ranges); if (ret) - goto err_free_phys; + goto err_access; kfree(dma_ranges); dma_ranges = NULL; if (!vfio_device_try_get_registration(&vdev->vdev)) { ret = -ENODEV; - goto err_free_phys; + goto err_access; } exp_info.ops = &vfio_pci_dmabuf_ops; @@ -311,6 +318,7 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags, list_add_tail(&priv->dmabufs_elm, &vdev->dmabufs); dma_resv_unlock(priv->dmabuf->resv); up_write(&vdev->memory_lock); + vfio_pci_core_access_end(vdev, idx); /* * dma_buf_fd() consumes the reference, when the file closes the dmabuf @@ -324,6 +332,8 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags, err_dev_put: vfio_device_put_registration(&vdev->vdev); +err_access: + vfio_pci_core_access_end(vdev, idx); err_free_phys: kfree(priv->phys_vec); err_free_priv: -- 2.43.0