[PULL 35/41] util/vfio-helper: Fix endianness in PCI config read/write functions

Cédric Le Goater posted 41 patches 3 weeks, 6 days ago
Maintainers: Yi Liu <yi.l.liu@intel.com>, Eric Auger <eric.auger@redhat.com>, Zhenzhong Duan <zhenzhong.duan@intel.com>, Paolo Bonzini <pbonzini@redhat.com>, Richard Henderson <richard.henderson@linaro.org>, Eduardo Habkost <eduardo@habkost.net>, "Michael S. Tsirkin" <mst@redhat.com>, Marcel Apfelbaum <marcel.apfelbaum@gmail.com>, Jason Wang <jasowang@redhat.com>, "Clément Mathieu--Drif" <clement.mathieu--drif@eviden.com>, Alexey Kardashevskiy <aik@ozlabs.ru>, John Levon <john.levon@nutanix.com>, Thanos Makatos <thanos.makatos@nutanix.com>, "Cédric Le Goater" <clg@redhat.com>, Alex Williamson <alex@shazbot.org>, Magnus Kulke <magnus.kulke@linux.microsoft.com>, Wei Liu <wei.liu@kernel.org>, Cornelia Huck <cohuck@redhat.com>, Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <alistair.francis@wdc.com>, Weiwei Li <liwei1518@gmail.com>, Daniel Henrique Barboza <dbarboza@ventanamicro.com>, Liu Zhiwei <zhiwei_liu@linux.alibaba.com>, Fabiano Rosas <farosas@suse.de>, Laurent Vivier <lvivier@redhat.com>
There is a newer version of this series
[PULL 35/41] util/vfio-helper: Fix endianness in PCI config read/write functions
Posted by Cédric Le Goater 3 weeks, 6 days ago
From: Farhan Ali <alifm@linux.ibm.com>

The VFIO pread/pwrite functions use little-endian data format. Currently, the
qemu_vfio_pci_read_config() and qemu_vfio_pci_write_config() don't correctly
convert from CPU native endian format to little-endian (and vice versa) when
using the pread/pwrite functions. Fix this by limiting read/write to 32 bits
and handling endian conversion in qemu_vfio_pci_read_config() and
qemu_vfio_pci_write_config().

Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260105222029.2423-1-alifm@linux.ibm.com
[ clg: Fixed typo in subject ]
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
 util/vfio-helpers.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
index c6195161637a16b4f26dc82f0297e43281a717f7..aab0bf9d485d41b7dc41a1e46449060777cca5e2 100644
--- a/util/vfio-helpers.c
+++ b/util/vfio-helpers.c
@@ -233,31 +233,36 @@ int qemu_vfio_pci_init_irq(QEMUVFIOState *s, EventNotifier *e,
     return 0;
 }
 
-static int qemu_vfio_pci_read_config(QEMUVFIOState *s, void *buf,
+static int qemu_vfio_pci_read_config(QEMUVFIOState *s, uint32_t *buf,
                                      int size, int ofs)
 {
     int ret;
+    uint32_t val_le;
 
     trace_qemu_vfio_pci_read_config(buf, ofs, size,
                                     s->config_region_info.offset,
                                     s->config_region_info.size);
     assert(QEMU_IS_ALIGNED(s->config_region_info.offset + ofs, size));
     ret = RETRY_ON_EINTR(
-        pread(s->device, buf, size, s->config_region_info.offset + ofs)
+        pread(s->device, &val_le, size, s->config_region_info.offset + ofs)
     );
+
+    *buf = le32_to_cpu(val_le);
     return ret == size ? 0 : -errno;
 }
 
-static int qemu_vfio_pci_write_config(QEMUVFIOState *s, void *buf, int size, int ofs)
+static int qemu_vfio_pci_write_config(QEMUVFIOState *s, uint32_t *buf, int size, int ofs)
 {
     int ret;
+    uint32_t val_le;
 
+    val_le = cpu_to_le32(*buf);
     trace_qemu_vfio_pci_write_config(buf, ofs, size,
                                      s->config_region_info.offset,
                                      s->config_region_info.size);
     assert(QEMU_IS_ALIGNED(s->config_region_info.offset + ofs, size));
     ret = RETRY_ON_EINTR(
-        pwrite(s->device, buf, size, s->config_region_info.offset + ofs)
+        pwrite(s->device, &val_le, size, s->config_region_info.offset + ofs)
     );
     return ret == size ? 0 : -errno;
 }
@@ -296,7 +301,7 @@ static int qemu_vfio_init_pci(QEMUVFIOState *s, const char *device,
 {
     int ret;
     int i;
-    uint16_t pci_cmd;
+    uint32_t pci_cmd;
     struct vfio_group_status group_status = { .argsz = sizeof(group_status) };
     struct vfio_iommu_type1_info *iommu_info = NULL;
     size_t iommu_info_size = sizeof(*iommu_info);
-- 
2.52.0