[PATCH v3 10/24] vfio: Enforce preserved devices are retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD

David Matlack
2026-03-23T23:59:01Z

Enforce that files for incoming (preserved by previous kernel) VFIO
devices are retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD rather than by
opening the corresponding VFIO character device or via
VFIO_GROUP_GET_DEVICE_FD.

Both of these methods would result in VFIO initializing the device
without access to the preserved state of the device passed by the
previous kernel.

Reviewed-by: Pranjal Shrivastava <praan@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/vfio/device_cdev.c | 4 ++++
drivers/vfio/group.c | 9 +++++++++
drivers/vfio/pci/vfio_pci_liveupdate.c | 6 ++++++
drivers/vfio/vfio.h | 18 ++++++++++++++++++
4 files changed, 37 insertions(+)

diff --git a/drivers/vfio/device_cdev.c b/drivers/vfio/device_cdev.c
index edf322315a41..6844684a3d8e 100644
--- a/drivers/vfio/device_cdev.c
+++ b/drivers/vfio/device_cdev.c
@@ -91,6 +91,10 @@ int vfio_device_fops_cdev_open(struct inode *inode, struct file *file)
struct vfio_device *device = container_of(inode->i_cdev,
struct vfio_device, cdev);

+ /* Device file must be retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD */
+ if (vfio_liveupdate_incoming_is_preserved(device))
+ return -EBUSY;
+
return vfio_device_cdev_open(device, &file);
}

diff --git a/drivers/vfio/group.c b/drivers/vfio/group.c
index 4f15016d2a5f..0fa9761b13d3 100644
--- a/drivers/vfio/group.c
+++ b/drivers/vfio/group.c
@@ -311,6 +311,15 @@ static int vfio_group_ioctl_get_device_fd(struct vfio_group *group,
if (IS_ERR(device))
return PTR_ERR(device);

+ /*
+ * This device was preserved across a Live Update. Accessing it via
+ * VFIO_GROUP_GET_DEVICE_FD is not allowed.
+ */
+ if (vfio_liveupdate_incoming_is_preserved(device)) {
+ vfio_device_put_registration(device);
+ return -EBUSY;
+ }
+
fd = FD_ADD(O_CLOEXEC, vfio_device_open_file(device));
if (fd < 0)
vfio_device_put_registration(device);
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index b960ec3ffbf2..6f760ace7065 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -47,6 +47,12 @@
* ...
* ioctl(session_fd, LIVEUPDATE_SESSION_FINISH, ...);
*
+ * .. note::
+ * After kexec, if a device was preserved by the previous kernel, attempting
+ * to open a new file for the device via its character device
+ * (``/dev/vfio/devices/X``) or via ``VFIO_GROUP_GET_DEVICE_FD`` will fail
+ * with ``-EBUSY``.
+ *
* Restrictions
* ============
*
diff --git a/drivers/vfio/vfio.h b/drivers/vfio/vfio.h
index 50128da18bca..8fcc98cf9577 100644
--- a/drivers/vfio/vfio.h
+++ b/drivers/vfio/vfio.h
@@ -11,6 +11,7 @@
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/vfio.h>
+#include <linux/pci.h>

struct iommufd_ctx;
struct iommu_group;
@@ -462,4 +463,21 @@ static inline void vfio_device_debugfs_init(struct vfio_device *vdev) { }
static inline void vfio_device_debugfs_exit(struct vfio_device *vdev) { }
#endif /* CONFIG_VFIO_DEBUGFS */

+#ifdef CONFIG_PCI_LIVEUPDATE
+static inline bool vfio_liveupdate_incoming_is_preserved(struct vfio_device *device)
+{
+ struct device *d = device->dev;
+
+ if (dev_is_pci(d))
+ return to_pci_dev(d)->liveupdate_incoming;
+
+ return false;
+}
+#else
+static inline bool vfio_liveupdate_incoming_is_preserved(struct vfio_device *device)
+{
+ return false;
+}
+#endif /* CONFIG_PCI_LIVEUPDATE */
+
#endif
--
2.53.0.983.g0bb29b3bc5-goog