From: "Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org>
To: linux-coco@lists.linux.dev
Cc: "Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org>,
Ackerley Tng <ackerleytng@google.com>,
Alex Williamson <alex@shazbot.org>,
David Woodhouse <dwmw2@infradead.org>,
David Hildenbrand <david@kernel.org>,
Jason Gunthorpe <jgg@ziepe.ca>,
"Joerg Roedel (AMD)" <joro@8bytes.org>,
Kevin Tian <kevin.tian@intel.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Robin Murphy <robin.murphy@arm.com>,
Sean Christopherson <seanjc@google.com>,
Will Deacon <will@kernel.org>, Alexey Kardashevskiy <aik@amd.com>,
Xu Yilun <yilun.xu@linux.intel.com>,
Catalin Marinas <catalin.marinas@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Steven Price <steven.price@arm.com>,
Fred Griffoul <griffoul@gmail.com>,
iommu@lists.linux.dev, kvm@vger.kernel.org,
patches@lists.linux.dev
Subject: [RFC PATCH v2 07/13] vfio/pci: Restrict host BAR access for guest_memfd providers
Date: Sat, 17 Oct 2026 13:01:43 +0530 [thread overview]
Message-ID: <20261017073149.1303738-8-aneesh.kumar@kernel.org> (raw)
In-Reply-To: <20261017073149.1303738-1-aneesh.kumar@kernel.org>
Add the access and invalidation helpers needed by a PCI guest_memfd
provider. Check shared-range attributes for BAR read/write and ioeventfd
access, and revoke shared guest mappings when VFIO changes device state.
Reject new VFIO mmap and dma-buf exports while a provider is attached.
Cc: Alex Williamson <alex@shazbot.org>
Cc: Sean Christopherson <seanjc@google.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: kvm@vger.kernel.org
Cc: patches@lists.linux.dev
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
drivers/vfio/pci/Kconfig | 11 +++
drivers/vfio/pci/Makefile | 1 +
drivers/vfio/pci/vfio_pci_core.c | 9 ++-
drivers/vfio/pci/vfio_pci_dmabuf.c | 10 +++
drivers/vfio/pci/vfio_pci_gmem.h | 15 ++++
drivers/vfio/pci/vfio_pci_gmem_access.c | 101 ++++++++++++++++++++++++
drivers/vfio/pci/vfio_pci_rdwr.c | 13 ++-
include/linux/vfio_pci_core.h | 22 ++++++
8 files changed, 178 insertions(+), 4 deletions(-)
create mode 100644 drivers/vfio/pci/vfio_pci_gmem.h
create mode 100644 drivers/vfio/pci/vfio_pci_gmem_access.c
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig
index 296bf01e185e..e5dedf3e4a65 100644
--- a/drivers/vfio/pci/Kconfig
+++ b/drivers/vfio/pci/Kconfig
@@ -55,6 +55,17 @@ config VFIO_PCI_ZDEV_KVM
To enable s390x KVM vfio-pci extensions, say Y.
+config VFIO_PCI_GMEM
+ bool "VFIO PCI device guest_memfd resource provider"
+ depends on VFIO_PCI && IOMMUFD && KVM
+ depends on KVM_GUEST_MEMFD
+ help
+ Allow the VFIO PCI device fd to provide BAR PFNs to guest_memfd,
+ including confidential-device range conversion through its
+ existing IOMMUFD vDEVICE. This requires a capable TSM backend.
+ Shared access is revoked before private range mapping and is
+ restored only after private mappings and device state permit it.
+
config VFIO_PCI_DMABUF
def_bool y if VFIO_PCI_CORE && PCI_P2PDMA && DMA_SHARED_BUFFER
diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile
index 6138f1bf241d..d491b38ad9c2 100644
--- a/drivers/vfio/pci/Makefile
+++ b/drivers/vfio/pci/Makefile
@@ -3,6 +3,7 @@
vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o
vfio-pci-core-$(CONFIG_VFIO_PCI_ZDEV_KVM) += vfio_pci_zdev.o
vfio-pci-core-$(CONFIG_VFIO_PCI_DMABUF) += vfio_pci_dmabuf.o
+vfio-pci-core-$(CONFIG_VFIO_PCI_GMEM) += vfio_pci_gmem_access.o
obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o
vfio-pci-y := vfio_pci.o
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 795b4ab1174e..1258343a6832 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -1713,7 +1713,10 @@ static void vfio_pci_zap_bars(struct vfio_pci_core_device *vdev)
loff_t end = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_ROM_REGION_INDEX);
loff_t len = end - start;
- unmap_mapping_range(core_vdev->inode->i_mapping, start, len, true);
+ /* An attached provider excludes every VFIO BAR VMA. */
+ if (!vdev->gmem)
+ unmap_mapping_range(core_vdev->inode->i_mapping, start, len, true);
+ vfio_pci_gmem_invalidate(vdev);
}
void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_core_device *vdev)
@@ -1838,6 +1841,10 @@ int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma
u64 phys_len, req_len, pgoff, req_start;
void __iomem *bar_io;
+ guard(rwsem_read)(&vdev->memory_lock);
+ if (vdev->gmem)
+ return -EBUSY;
+
index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);
if (index >= VFIO_PCI_NUM_REGIONS + vdev->num_regions)
diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c
index c16f460c01d6..b3ae2d97629f 100644
--- a/drivers/vfio/pci/vfio_pci_dmabuf.c
+++ b/drivers/vfio/pci/vfio_pci_dmabuf.c
@@ -306,6 +306,16 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
/* dma_buf_put() now frees priv */
INIT_LIST_HEAD(&priv->dmabufs_elm);
down_write(&vdev->memory_lock);
+ /*
+ * dma-buf consumers bypass guest_memfd range access checks, and their
+ * mappings are not revoked by conversion to private memory. Exclude
+ * exports while attached; memory_lock serializes this with attachment.
+ */
+ if (vdev->gmem) {
+ up_write(&vdev->memory_lock);
+ dma_buf_put(priv->dmabuf);
+ return -EBUSY;
+ }
dma_resv_lock(priv->dmabuf->resv, NULL);
priv->revoked = !__vfio_pci_memory_enabled(vdev);
list_add_tail(&priv->dmabufs_elm, &vdev->dmabufs);
diff --git a/drivers/vfio/pci/vfio_pci_gmem.h b/drivers/vfio/pci/vfio_pci_gmem.h
new file mode 100644
index 000000000000..a8edd20357e7
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_gmem.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef VFIO_PCI_GMEM_H
+#define VFIO_PCI_GMEM_H
+
+#include <linux/guest_memfd.h>
+
+struct iommufd_vdevice;
+struct vfio_pci_core_device;
+
+struct vfio_pci_gmem {
+ struct guest_memfd *gmem;
+ struct iommufd_vdevice *ivdev;
+};
+
+#endif /* VFIO_PCI_GMEM_H */
diff --git a/drivers/vfio/pci/vfio_pci_gmem_access.c b/drivers/vfio/pci/vfio_pci_gmem_access.c
new file mode 100644
index 000000000000..40219f05345b
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_gmem_access.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Shared/private access and guest revocation are controlled by guest_memfd. */
+#include <linux/guest_memfd.h>
+#include <linux/iommufd.h>
+#include <linux/vfio_pci_core.h>
+
+#include "vfio_pci_gmem.h"
+#include "vfio_pci_priv.h"
+
+/**
+ * vfio_pci_gmem_invalidate() - notify KVM of BAR mappings invalidate
+ * @vdev: VFIO PCI device whose BAR translations are being revoked
+ *
+ * Called by vfio_pci_zap_bars() after it removes host BAR mappings. Notify
+ * guest_memfd synchronously so KVM removes the corresponding shared guest
+ * mappings. This helper does not remove host mappings or change attributes.
+ * Skip notification if no provider is attached.
+ *
+ */
+void vfio_pci_gmem_invalidate(struct vfio_pci_core_device *vdev)
+{
+ struct vfio_pci_gmem *ctx = vdev->gmem;
+
+ lockdep_assert_held_write(&vdev->memory_lock);
+ if (ctx)
+ ctx->gmem->invalidate(ctx->gmem);
+}
+
+/**
+ * vfio_pci_gmem_access_allowed() - check a host BAR access against its range
+ * @vdev: VFIO PCI device supplying the BAR
+ * @offset: byte offset in the VFIO region namespace
+ * @size: access length in bytes
+ *
+ * Consult completed guest_memfd attributes for the requested interval.
+ * Private mappings in another interval do not block this access. Try the
+ * inode lock instead of waiting in the reverse order from conversion.
+ *
+ * Return: true when the requested interval is accessible.
+ */
+bool vfio_pci_gmem_access_allowed(struct vfio_pci_core_device *vdev,
+ u64 offset, u64 size)
+{
+ struct vfio_pci_gmem *ctx = vdev->gmem;
+
+ lockdep_assert_held(&vdev->memory_lock);
+ if (!ctx)
+ return true;
+
+ /* Attachment publishes the context before resolving its vDEVICE. */
+ if (!ctx->ivdev)
+ return false;
+
+ return ctx->gmem->host_accessible(ctx->gmem,
+ offset, size);
+}
+
+/**
+ * vfio_pci_gmem_io_access_allowed() - resolve a mapped BAR address
+ * @vdev: VFIO PCI device supplying the iomap
+ * @io: address used by ordinary VFIO read, write or ioeventfd
+ * @size: access width in bytes
+ *
+ * Standard BAR iomaps are cached in barmap. Resolve those to file offsets
+ * before applying range admission. Generic VFIO's remaining memory I/O uses
+ * a temporary ROM iomap, which cannot be bound to a device guest_memfd.
+ * Callers supply VFIO's own validated iomap pointers.
+ *
+ * Return: true when the I/O interval is accessible.
+ */
+bool vfio_pci_gmem_io_access_allowed(struct vfio_pci_core_device *vdev,
+ void __iomem *io, size_t size)
+{
+ unsigned long addr = (unsigned long)io;
+ int bar;
+
+ lockdep_assert_held(&vdev->memory_lock);
+ if (!vdev->gmem)
+ return vfio_pci_gmem_access_allowed(vdev, 0, size);
+
+ for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
+ unsigned long base = (unsigned long)vdev->barmap[bar];
+ u64 offset;
+
+ if (!base || addr < base)
+ continue;
+
+ offset = addr - base;
+ if (offset >= pci_resource_len(vdev->pdev, bar))
+ continue;
+
+ if (size > pci_resource_len(vdev->pdev, bar) - offset)
+ return false;
+
+ return vfio_pci_gmem_access_allowed(vdev,
+ VFIO_PCI_INDEX_TO_OFFSET(bar) + offset, size);
+ }
+ /* The ROM has no private provider mappings, but lifecycle checks apply. */
+ return vfio_pci_gmem_access_allowed(vdev,
+ VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_ROM_REGION_INDEX), size);
+}
diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
index 7f14dd46de17..54c1b3d2f725 100644
--- a/drivers/vfio/pci/vfio_pci_rdwr.c
+++ b/drivers/vfio/pci/vfio_pci_rdwr.c
@@ -44,7 +44,9 @@ int vfio_pci_core_iowrite##size(struct vfio_pci_core_device *vdev, \
{ \
if (test_mem) { \
down_read(&vdev->memory_lock); \
- if (!__vfio_pci_memory_enabled(vdev)) { \
+ if (!__vfio_pci_memory_enabled(vdev) || \
+ !vfio_pci_gmem_io_access_allowed(vdev, io, \
+ sizeof(u##size))) { \
up_read(&vdev->memory_lock); \
return -EIO; \
} \
@@ -70,7 +72,9 @@ int vfio_pci_core_ioread##size(struct vfio_pci_core_device *vdev, \
{ \
if (test_mem) { \
down_read(&vdev->memory_lock); \
- if (!__vfio_pci_memory_enabled(vdev)) { \
+ if (!__vfio_pci_memory_enabled(vdev) || \
+ !vfio_pci_gmem_io_access_allowed(vdev, io, \
+ sizeof(u##size))) { \
up_read(&vdev->memory_lock); \
return -EIO; \
} \
@@ -380,7 +384,10 @@ static int vfio_pci_ioeventfd_handler(void *opaque, void *unused)
if (ioeventfd->test_mem) {
if (!down_read_trylock(&vdev->memory_lock))
return 1; /* Lock contended, use thread */
- if (!__vfio_pci_memory_enabled(vdev)) {
+ if (!__vfio_pci_memory_enabled(vdev) ||
+ !vfio_pci_gmem_access_allowed(vdev,
+ VFIO_PCI_INDEX_TO_OFFSET(ioeventfd->bar) +
+ ioeventfd->pos, ioeventfd->count)) {
up_read(&vdev->memory_lock);
return 0;
}
diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h
index dc15b462126e..9f8aa81eb1c9 100644
--- a/include/linux/vfio_pci_core.h
+++ b/include/linux/vfio_pci_core.h
@@ -151,8 +151,30 @@ struct vfio_pci_core_device {
struct rw_semaphore memory_lock;
atomic_t mmap_count;
struct list_head dmabufs;
+ /* Attached provider; publication/removal require memory_lock for write. */
+ struct vfio_pci_gmem *gmem;
};
+#if IS_ENABLED(CONFIG_VFIO_PCI_GMEM)
+void vfio_pci_gmem_invalidate(struct vfio_pci_core_device *vdev);
+bool vfio_pci_gmem_access_allowed(struct vfio_pci_core_device *vdev,
+ u64 offset, u64 size);
+bool vfio_pci_gmem_io_access_allowed(struct vfio_pci_core_device *vdev,
+ void __iomem *io, size_t size);
+#else
+static inline void vfio_pci_gmem_invalidate(struct vfio_pci_core_device *vdev) {}
+static inline bool vfio_pci_gmem_access_allowed(struct vfio_pci_core_device *vdev,
+ u64 offset, u64 size)
+{
+ return true;
+}
+static inline bool vfio_pci_gmem_io_access_allowed(struct vfio_pci_core_device *vdev,
+ void __iomem *io, size_t size)
+{
+ return true;
+}
+#endif
+
enum vfio_pci_io_width {
VFIO_PCI_IO_WIDTH_1 = 1,
VFIO_PCI_IO_WIDTH_2 = 2,
--
2.43.0
next prev parent reply other threads:[~2026-10-17 7:32 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-17 7:31 [RFC PATCH v2 00/13] KVM/VFIO: guest_memfd support for device MMIO resources Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 01/13] KVM: guest_memfd: Support PFN-backed resource providers Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 02/13] KVM: guest_memfd: Support private/shared conversion of device memory Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 03/13] iommufd: Support MMIO provider attachment to vDEVICEs Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 04/13] KVM: guest_memfd: Add device provider access callbacks Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 05/13] vfio/pci: Track userspace BAR mappings Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 06/13] vfio: Dispatch guest_memfd provider operations through the filesystem Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` Aneesh Kumar K.V (Arm) [this message]
2026-10-17 7:31 ` [RFC PATCH v2 08/13] vfio/pci: Provide guest_memfd backing for PCI BARs Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 09/13] KVM: guest_memfd: Add a provider detach callback Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 10/13] vfio/pci: Detach guest_memfd access before teardown Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 11/13] KVM: guest_memfd: Remove device mappings on final close Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 12/13] KVM: Invalidate guest_memfd mappings before removing memslot bindings Aneesh Kumar K.V (Arm)
2026-10-17 7:31 ` [RFC PATCH v2 13/13] vfio/pci: Allow VFIO BAR mmap with an attached guest_memfd Aneesh Kumar K.V (Arm)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261017073149.1303738-8-aneesh.kumar@kernel.org \
--to=aneesh.kumar@kernel.org \
--cc=ackerleytng@google.com \
--cc=aik@amd.com \
--cc=alex@shazbot.org \
--cc=catalin.marinas@arm.com \
--cc=david@kernel.org \
--cc=dwmw2@infradead.org \
--cc=griffoul@gmail.com \
--cc=iommu@lists.linux.dev \
--cc=jgg@ziepe.ca \
--cc=joro@8bytes.org \
--cc=kevin.tian@intel.com \
--cc=kvm@vger.kernel.org \
--cc=linux-coco@lists.linux.dev \
--cc=patches@lists.linux.dev \
--cc=pbonzini@redhat.com \
--cc=robin.murphy@arm.com \
--cc=seanjc@google.com \
--cc=steven.price@arm.com \
--cc=suzuki.poulose@arm.com \
--cc=will@kernel.org \
--cc=yilun.xu@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox