All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number
@ 2026-06-13 17:43 Pranjal Arya
  2026-06-13 17:43 ` [PATCH RFC 1/3] vfio/pci: Virtualize and scrub Device Serial Number from guests Pranjal Arya
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Pranjal Arya @ 2026-06-13 17:43 UTC (permalink / raw)
  To: Alex Williamson, Bjorn Helgaas, David Matlack, Shuah Khan
  Cc: linux-arm-msm, kvm, linux-kernel, linux-pci, linux-kselftest,
	Pranjal Shrivastava, Manivannan Sadhasivam, Pranjal Arya

vfio-pci has no perm_bits entry for the PCIe Device Serial Number (DSN)
Extended Capability, so guest reads of the serial
number currently fall through to the physical device.  The DSN is a
unique, persistent hardware serial number that identifies the physical
component (the functions of a Multi-Function Device report the same
value; Root Complex integrated Endpoints may implement it independently),
so exposing it lets a guest fingerprint the host hardware and correlate
it across VMs.  For multi-tenant passthrough this is an unnecessary
host-identifier leak.

Series:

  Patch 1 fully virtualizes the DSN capability (header + both serial
  dwords) and scrubs the serial in the virtualized config space, so guests
  read a zeroed serial while the capability stays visible.

  Patch 2 adds a VFIO_DEVICE_FEATURE_PCI_DSN device feature so a trusted
  userspace VMM can GET/SET the serial presented to the guest, for use
  cases that need a stable but non-host-identifying serial (e.g. across
  live migration between different physical devices).

  Patch 3 adds a selftest: scrub-by-default, guest-write rejection,
  PROBE/SET/GET, set-twice, persistence-across-reset, and bad-argsz.

Position on default-on (the main RFC question):
  I propose scrubbing by default rather than opt-in.  Rationale:
  - A passed-through DSN is not meaningful to a guest today: the value
    identifies the specific physical device, so any guest that keyed off
    it would already break on migration or reassignment.
  - vfio-pci already virtualizes/zeroes other identifying or host-specific
    config state. The DSN is an outlier passed through unfiltered.
  - Patch 2 provides an explicit escape hatch (VMM-set serial) for the
    rare consumer that wants a stable identity.
  If maintainers prefer opt-in, the scrub can be gated behind a module
  param or a per-device feature flag.

Concurrency:
  The guest config-space read path is unlocked and reads the DSN as two
  independent 32-bit accesses, so the kernel cannot make a 64-bit guest
  read atomic.  Patch 2 uses WRITE_ONCE/READ_ONCE for per-dword
  consistency and documents that a guest reading across a SET may see an
  old/new mix, exactly as HW may tear a 64-bit read of a register pair.
  Serializing concurrent SET callers is the VMM's responsibility.

Lifetime:
  The presented serial lives only in vconfig: it persists across runtime
  FLR/SBR and is cleared on device fd close (per-open).

SR-IOV:
  Per the SR-IOV spec a PF's DSN applies to all its VFs, and a VF that
  implements DSN must report the same value as its PF.  vfio-pci exposes
  only the assigned device's own config space and applies no VF-specific
  transform to the DSN bytes, so a VF that implements DSN (whose value is
  the PF's host serial) is scrubbed like a PF, and a VF that omits the
  capability (the spec-recommended case) exposes no serial.  The selftest
  covers VFs when run against a VF BDF that exposes DSN.

Testing (under QEMU with full VFIO device assignment via IOMMUFD); in
every configuration all of the selftest's cases passed with none skipped
or failing:
  - x86_64 (intel-iommu), e1000e PF with DSN: all cases passed.
  - arm64 (smmuv3), e1000e PF with DSN: all cases passed.
  - x86_64 SR-IOV: an igb PF was given 1 VF that implements a DSN cap in a
    realistic extended-capability chain (AER -> ARI -> DSN); the VF was
    bound to vfio-pci and the selftest run against it: all cases passed.
    This exercises the spec case where a VF's DSN mirrors the PF host
    serial.
  - The SR-IOV run used a kernel built with KASAN + PROVE_LOCKING; no KASAN
    reports, lockdep splats, or warnings were produced.

Signed-off-by: Pranjal Arya <pranjal.arya@oss.qualcomm.com>
---
Pranjal Arya (3):
      vfio/pci: Virtualize and scrub Device Serial Number from guests
      vfio/pci: Allow userspace to set a virtual Device Serial Number
      selftests/vfio: Add PCIe Device Serial Number test

 MAINTAINERS                                      |   6 +
 drivers/vfio/pci/vfio_pci_config.c               |  98 +++++++++++
 drivers/vfio/pci/vfio_pci_core.c                 |   2 +
 drivers/vfio/pci/vfio_pci_priv.h                 |   2 +
 include/uapi/linux/pci_regs.h                    |   5 +
 include/uapi/linux/vfio.h                        |  18 ++
 tools/testing/selftests/vfio/Makefile            |   1 +
 tools/testing/selftests/vfio/vfio_pci_dsn_test.c | 206 +++++++++++++++++++++++
 8 files changed, 338 insertions(+)
---
base-commit: c425609d6ac4012c8bbf01ec2e10e801b1923a7b
change-id: 20260613-pcie_vfio-48506602ec6a

Best regards,
--  
Pranjal Arya <pranjal.arya@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH RFC 1/3] vfio/pci: Virtualize and scrub Device Serial Number from guests
  2026-06-13 17:43 [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number Pranjal Arya
@ 2026-06-13 17:43 ` Pranjal Arya
  2026-06-13 17:55   ` sashiko-bot
  2026-06-13 17:43 ` [PATCH RFC 2/3] vfio/pci: Allow userspace to set a virtual Device Serial Number Pranjal Arya
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Pranjal Arya @ 2026-06-13 17:43 UTC (permalink / raw)
  To: Alex Williamson, Bjorn Helgaas, David Matlack, Shuah Khan
  Cc: linux-arm-msm, kvm, linux-kernel, linux-pci, linux-kselftest,
	Pranjal Shrivastava, Manivannan Sadhasivam, Pranjal Arya

The PCIe Device Serial Number (DSN) Extended Capability reports a unique,
persistent hardware serial number (PCIe r6.2 sec 7.9.3).  The value
identifies the physical component: per the spec the functions of a
Multi-Function Device that implement the capability report the same DSN,
so a single value can fingerprint a whole physical device.  Root Complex
integrated Endpoints (RCiEPs) may implement the capability independently
and are not required to share their value with other RCiEPs of the same
Root Complex, but each such value is still a stable, host-specific
identifier.

vfio-pci has no perm_bits entry for the DSN capability, so guest reads of
the serial number fall through to the physical device.  This leaks a
stable hardware identifier into the guest that can be used to fingerprint
the host device and correlate it across VMs, which is undesirable for
multi-tenant passthrough.

Add a perm_bits initializer that fully virtualizes the DSN capability:
the header dword and both serial-number dwords (PCI_DSN_CAP,
PCI_DSN_LOW_DW, PCI_DSN_HIGH_DW) are marked ALL_VIRT/NO_WRITE so all
reads are served from the virtualized config space rather than hardware
and writes are denied (the DSN is read-only state).  Scrub the serial in
vconfig during vfio_ecap_init() so guests read a zeroed serial while the
capability remains visible.  Add the DSN register-offset defines to
pci_regs.h.

The capability length used by alloc_perm_bits() comes from the existing
pci_ext_cap_length[PCI_EXT_CAP_ID_DSN] = PCI_EXT_CAP_DSN_SIZEOF (12),
which covers the 4-byte header plus the 8-byte serial.

SR-IOV: per the SR-IOV spec a PF's DSN applies to all of its VFs, and a
VF that implements the DSN capability must report the same value as its
PF.  vfio-pci exposes only the assigned device's own config space to the
guest, and neither the vconfig fill nor the vfio_ecap_init() walk applies
any VF-specific transform to the DSN bytes, so the DSN capability is
virtualized and scrubbed for a VF exactly as for a PF.  Therefore a VF
that implements DSN (whose value is the PF's host serial) is scrubbed,
and a VF that omits the capability (the spec-recommended case) exposes no
serial to scrub.

Variant drivers (mlx5-vfio-pci, hisi-acc-vfio-pci, nvgrace-gpu-vfio-pci,
virtio-vfio-pci, etc.) build on vfio-pci-core and share this config-space
path and perm_bits table, so the scrub applies to them as well.

The scrub is the default because a guest cannot rely on a meaningful DSN
through vfio-pci in general (it identifies the physical device, which
varies across assignment and migration). The following patch lets the VMM
present a chosen serial where a stable identity is required.

Signed-off-by: Pranjal Arya <pranjal.arya@oss.qualcomm.com>
---
 drivers/vfio/pci/vfio_pci_config.c | 39 ++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/pci_regs.h      |  5 +++++
 2 files changed, 44 insertions(+)

diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index a10ed733f0e3..24dfeb43cb71 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -1085,6 +1085,31 @@ static int __init init_pci_ext_cap_pwr_perm(struct perm_bits *perm)
 	return 0;
 }
 
+/*
+ * The Device Serial Number is a unique, persistent, per-device identifier.
+ * Passing the physical serial number through to a guest leaks an identifier
+ * that can be used to fingerprint and correlate the host device across VMs
+ * and tenants.  Virtualize the whole capability so reads come from vconfig
+ * (which is scrubbed during init, see vfio_ecap_init()) instead of hardware,
+ * and disallow writes (the DSN is read-only hardware state anyway).
+ */
+static int __init init_pci_ext_cap_dsn_perm(struct perm_bits *perm)
+{
+	if (alloc_perm_bits(perm, pci_ext_cap_length[PCI_EXT_CAP_ID_DSN]))
+		return -ENOMEM;
+
+	/*
+	 * Virtualize the whole capability: the header (offset 0) plus the
+	 * two serial-number dwords (offsets 4 and 8).  All reads are then
+	 * served from vconfig (scrubbed in vfio_ecap_init()) rather than
+	 * hardware, and writes are denied since the DSN is read-only state.
+	 */
+	p_setd(perm, 0, ALL_VIRT, NO_WRITE);
+	p_setd(perm, 4, ALL_VIRT, NO_WRITE);
+	p_setd(perm, 8, ALL_VIRT, NO_WRITE);
+	return 0;
+}
+
 /*
  * Initialize the shared permission tables
  */
@@ -1100,6 +1125,7 @@ void vfio_pci_uninit_perm_bits(void)
 
 	free_perm_bits(&ecap_perms[PCI_EXT_CAP_ID_ERR]);
 	free_perm_bits(&ecap_perms[PCI_EXT_CAP_ID_PWR]);
+	free_perm_bits(&ecap_perms[PCI_EXT_CAP_ID_DSN]);
 }
 
 int __init vfio_pci_init_perm_bits(void)
@@ -1120,6 +1146,7 @@ int __init vfio_pci_init_perm_bits(void)
 	/* Extended capabilities */
 	ret |= init_pci_ext_cap_err_perm(&ecap_perms[PCI_EXT_CAP_ID_ERR]);
 	ret |= init_pci_ext_cap_pwr_perm(&ecap_perms[PCI_EXT_CAP_ID_PWR]);
+	ret |= init_pci_ext_cap_dsn_perm(&ecap_perms[PCI_EXT_CAP_ID_DSN]);
 	ecap_perms[PCI_EXT_CAP_ID_VNDR].writefn = vfio_raw_config_write;
 	ecap_perms[PCI_EXT_CAP_ID_DVSEC].writefn = vfio_raw_config_write;
 
@@ -1702,6 +1729,18 @@ static int vfio_ecap_init(struct vfio_pci_core_device *vdev)
 		if (ret)
 			return ret;
 
+		/*
+		 * Scrub the physical Device Serial Number from the
+		 * virtualized config space so the guest cannot read the
+		 * host device's unique identifier.  The capability is fully
+		 * virtualized (see init_pci_ext_cap_dsn_perm()), so reads
+		 * return this scrubbed value rather than hardware.  The user
+		 * can present a chosen serial via VFIO_DEVICE_FEATURE_PCI_DSN.
+		 */
+		if (ecap == PCI_EXT_CAP_ID_DSN)
+			memset(&vdev->vconfig[epos + PCI_DSN_LOW_DW], 0,
+			       sizeof(__le64));
+
 		/*
 		 * If we're just using this capability to anchor the list,
 		 * hide the real ID.  Only count real ecaps.  XXX PCI spec
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index facaa324bd86..bd0ae9decc00 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -768,6 +768,11 @@
 #define PCI_EXT_CAP_DSN_SIZEOF	12
 #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
 
+/* Device Serial Number */
+#define PCI_DSN_CAP		0x00	/* Capability header */
+#define PCI_DSN_LOW_DW		0x04	/* Serial number, lower dword */
+#define PCI_DSN_HIGH_DW		0x08	/* Serial number, upper dword */
+
 /* Advanced Error Reporting */
 #define PCI_ERR_UNCOR_STATUS	0x04	/* Uncorrectable Error Status */
 #define  PCI_ERR_UNC_UND	0x00000001	/* Undefined */

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC 2/3] vfio/pci: Allow userspace to set a virtual Device Serial Number
  2026-06-13 17:43 [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number Pranjal Arya
  2026-06-13 17:43 ` [PATCH RFC 1/3] vfio/pci: Virtualize and scrub Device Serial Number from guests Pranjal Arya
@ 2026-06-13 17:43 ` Pranjal Arya
  2026-06-13 17:58   ` sashiko-bot
  2026-06-13 17:43 ` [PATCH RFC 3/3] selftests/vfio: Add PCIe Device Serial Number test Pranjal Arya
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Pranjal Arya @ 2026-06-13 17:43 UTC (permalink / raw)
  To: Alex Williamson, Bjorn Helgaas, David Matlack, Shuah Khan
  Cc: linux-arm-msm, kvm, linux-kernel, linux-pci, linux-kselftest,
	Pranjal Shrivastava, Manivannan Sadhasivam, Pranjal Arya

The preceding patch ("vfio/pci: Virtualize and scrub Device Serial
Number from guests") hides the physical PCIe Device Serial Number from
guests by zeroing it.  Some use cases instead need a stable but
non-host-identifying serial, for example to keep a consistent device
identity across live migration between different physical devices.

Add a VFIO_DEVICE_FEATURE_PCI_DSN device feature that lets the trusted
userspace VMM GET/SET the 64-bit serial number presented in the device's
virtualized config space.  SET writes the value into the virtualized DSN
capability (whose dwords are virtualized by the preceding patch, so guest
reads return it) and GET reads it back; PROBE reports support.  The
feature returns -ENOTTY for devices without a DSN capability.  Guest
writes remain disallowed.

The presented serial is stored only in vconfig: it persists across a
runtime FLR/Secondary Bus Reset (reset does not rebuild vconfig) and is
cleared when the device fd is closed (vfio_config_free()), i.e. it is
per-open.  A feature ioctl can only reach an opened device, whose vconfig
was allocated by vfio_config_init() during vfio_pci_core_enable().

This feature uses index 13, not the next sequential value 12.  Index 12
is already assigned to VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2 in
linux-next by commit d7140b5dde45
("vfio: Define uAPI for re-init initial bytes during the PRE_COPY phase")
(https://lore.kernel.org/r/20260317161753.18964-2-yishaih@nvidia.com).
Using 12 makes the core feature switch route the ioctl to the
migration-precopy handler, which returns -EINVAL; this was observed in
testing, hence index 13.

Signed-off-by: Pranjal Arya <pranjal.arya@oss.qualcomm.com>
---
 drivers/vfio/pci/vfio_pci_config.c | 59 ++++++++++++++++++++++++++++++++++++++
 drivers/vfio/pci/vfio_pci_core.c   |  2 ++
 drivers/vfio/pci/vfio_pci_priv.h   |  2 ++
 include/uapi/linux/vfio.h          | 18 ++++++++++++
 4 files changed, 81 insertions(+)

diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index 24dfeb43cb71..60c19129c814 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -2078,3 +2078,62 @@ bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt,
 	return false;
 }
 EXPORT_SYMBOL_GPL(vfio_pci_core_range_intersect_range);
+
+int vfio_pci_core_feature_dsn(struct vfio_pci_core_device *vdev, u32 flags,
+			      void __user *arg, size_t argsz)
+{
+	struct vfio_device_feature_pci_dsn dsn;
+	struct pci_dev *pdev = vdev->pdev;
+	__le32 *vserial;
+	int pos, ret;
+
+	/*
+	 * The DSN capability is virtualized in vconfig; locate it on the
+	 * physical device only to decide whether the feature is supported.
+	 * A feature ioctl can only reach an opened device, and vconfig is
+	 * allocated by vfio_config_init() during vfio_pci_core_enable() on
+	 * open, so vconfig is valid here.
+	 */
+	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DSN);
+	if (!pos)
+		return -ENOTTY;
+
+	ret = vfio_check_feature(flags, argsz,
+				 VFIO_DEVICE_FEATURE_GET |
+				 VFIO_DEVICE_FEATURE_SET,
+				 sizeof(dsn));
+	if (ret != 1)
+		return ret;
+
+	vserial = (__le32 *)&vdev->vconfig[pos + PCI_DSN_LOW_DW];
+
+	if (flags & VFIO_DEVICE_FEATURE_SET) {
+		if (copy_from_user(&dsn, arg, sizeof(dsn)))
+			return -EFAULT;
+
+		/*
+		 * The config-space read path (vfio_default_config_read())
+		 * does not hold a lock, and a guest reads the DSN as two
+		 * 32-bit dwords.  Store each dword with WRITE_ONCE() so a
+		 * concurrent guest read observes a consistent dword; a guest
+		 * reading the two halves around this update may see an
+		 * old/new mix, exactly as hardware may tear a 64-bit read of
+		 * a register pair.  This matches the DSN's read-only,
+		 * advisory nature.  Serializing concurrent SET callers is the
+		 * userspace VMM's responsibility.
+		 */
+		WRITE_ONCE(vserial[0], cpu_to_le32(lower_32_bits(dsn.serial_number)));
+		WRITE_ONCE(vserial[1], cpu_to_le32(upper_32_bits(dsn.serial_number)));
+		return 0;
+	}
+
+	/* VFIO_DEVICE_FEATURE_GET */
+	dsn.serial_number =
+		((u64)le32_to_cpu(READ_ONCE(vserial[1])) << 32) |
+		le32_to_cpu(READ_ONCE(vserial[0]));
+
+	if (copy_to_user(arg, &dsn, sizeof(dsn)))
+		return -EFAULT;
+
+	return 0;
+}
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index a28f1e99362c..08a98a796717 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -1572,6 +1572,8 @@ int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,
 		return vfio_pci_core_feature_token(vdev, flags, arg, argsz);
 	case VFIO_DEVICE_FEATURE_DMA_BUF:
 		return vfio_pci_core_feature_dma_buf(vdev, flags, arg, argsz);
+	case VFIO_DEVICE_FEATURE_PCI_DSN:
+		return vfio_pci_core_feature_dsn(vdev, flags, arg, argsz);
 	default:
 		return -ENOTTY;
 	}
diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
index fca9d0dfac90..dfb0c800e6f1 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -64,6 +64,8 @@ void vfio_pci_uninit_perm_bits(void);
 
 int vfio_config_init(struct vfio_pci_core_device *vdev);
 void vfio_config_free(struct vfio_pci_core_device *vdev);
+int vfio_pci_core_feature_dsn(struct vfio_pci_core_device *vdev, u32 flags,
+			      void __user *arg, size_t argsz);
 
 int vfio_pci_set_power_state(struct vfio_pci_core_device *vdev,
 			     pci_power_t state);
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 5de618a3a5ee..e5b8dfd3833f 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -1511,6 +1511,24 @@ struct vfio_device_feature_bus_master {
  */
 #define VFIO_DEVICE_FEATURE_DMA_BUF 11
 
+/**
+ * Upon VFIO_DEVICE_FEATURE_SET, set the PCIe Device Serial Number (DSN)
+ * presented to the user (guest) in the device's virtualized config space.
+ * By default vfio-pci scrubs the physical DSN to zero so the host device's
+ * unique identifier is not leaked; this feature lets the hypervisor present
+ * a chosen, per-VM synthetic serial instead (for example a stable but
+ * non-host-identifying value for migration).
+ *
+ * Upon VFIO_DEVICE_FEATURE_GET, read back the currently presented serial.
+ *
+ * The feature is only available for devices that expose a DSN capability.
+ * serial_number is the 64-bit serial in little-endian wire order.
+ */
+struct vfio_device_feature_pci_dsn {
+	__aligned_u64 serial_number;
+};
+#define VFIO_DEVICE_FEATURE_PCI_DSN 13
+
 struct vfio_region_dma_range {
 	__u64 offset;
 	__u64 length;

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC 3/3] selftests/vfio: Add PCIe Device Serial Number test
  2026-06-13 17:43 [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number Pranjal Arya
  2026-06-13 17:43 ` [PATCH RFC 1/3] vfio/pci: Virtualize and scrub Device Serial Number from guests Pranjal Arya
  2026-06-13 17:43 ` [PATCH RFC 2/3] vfio/pci: Allow userspace to set a virtual Device Serial Number Pranjal Arya
@ 2026-06-13 17:43 ` Pranjal Arya
  2026-06-13 18:01   ` sashiko-bot
  2026-06-13 18:56 ` [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number Alex Williamson
  2026-06-13 20:35 ` Pranjal Shrivastava
  4 siblings, 1 reply; 9+ messages in thread
From: Pranjal Arya @ 2026-06-13 17:43 UTC (permalink / raw)
  To: Alex Williamson, Bjorn Helgaas, David Matlack, Shuah Khan
  Cc: linux-arm-msm, kvm, linux-kernel, linux-pci, linux-kselftest,
	Pranjal Shrivastava, Manivannan Sadhasivam, Pranjal Arya

Add a selftest exercising the vfio-pci DSN handling:
 - the serial number is scrubbed to zero by default while the DSN
   capability remains present,
 - guest writes to the DSN bytes are rejected (value unchanged),
 - VFIO_DEVICE_FEATURE_PCI_DSN PROBE reflects DSN support,
 - SET/GET round-trips and is reflected in the guest-visible config
   space,
 - SET twice returns the latest value on GET,
 - the presented serial persists across a device reset, and
 - a short argsz is rejected with -EINVAL.

The tests skip when the assigned device has no DSN capability or does
not support reset.

Run with the device assigned to vfio-pci, e.g.:

  VFIO_SELFTESTS_BDF="0000:01:00.0" ./vfio_pci_dsn_test

Exercised under QEMU with full VFIO assignment via IOMMUFD: all of the
test's cases passed on x86_64 (intel-iommu) and arm64 (smmuv3) against an
emulated e1000e (which implements DSN), and on x86_64 against an SR-IOV
VF that implements DSN in an AER -> ARI -> DSN extended-capability chain.
The SR-IOV run used a KASAN + PROVE_LOCKING kernel with no reports.

Signed-off-by: Pranjal Arya <pranjal.arya@oss.qualcomm.com>
---
 MAINTAINERS                                      |   6 +
 tools/testing/selftests/vfio/Makefile            |   1 +
 tools/testing/selftests/vfio/vfio_pci_dsn_test.c | 206 +++++++++++++++++++++++
 3 files changed, 213 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 8629ed2aa82f..ed8e7df12021 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -28347,6 +28347,12 @@ L:	kvm@vger.kernel.org
 S:	Supported
 F:	drivers/vfio/pci/nvgrace-gpu/
 
+VFIO PCI DEVICE SERIAL NUMBER SELFTEST
+M:	Pranjal Arya <pranjal.arya@oss.qualcomm.com>
+L:	kvm@vger.kernel.org
+S:	Maintained
+F:	tools/testing/selftests/vfio/vfio_pci_dsn_test.c
+
 VFIO PCI DEVICE SPECIFIC DRIVERS
 R:	Jason Gunthorpe <jgg@nvidia.com>
 R:	Yishai Hadas <yishaih@nvidia.com>
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index e6e8cb52ab03..06e637573cf7 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -13,6 +13,7 @@ TEST_GEN_PROGS += vfio_pci_device_test
 TEST_GEN_PROGS += vfio_pci_device_init_perf_test
 TEST_GEN_PROGS += vfio_pci_driver_test
 TEST_GEN_PROGS += vfio_pci_sriov_uapi_test
+TEST_GEN_PROGS += vfio_pci_dsn_test
 
 TEST_FILES += scripts/cleanup.sh
 TEST_FILES += scripts/lib.sh
diff --git a/tools/testing/selftests/vfio/vfio_pci_dsn_test.c b/tools/testing/selftests/vfio/vfio_pci_dsn_test.c
new file mode 100644
index 000000000000..d7652ad725f4
--- /dev/null
+++ b/tools/testing/selftests/vfio/vfio_pci_dsn_test.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Tests for the PCIe Device Serial Number (DSN) handling in vfio-pci:
+ *  - the physical serial is scrubbed (read as zero) by default,
+ *  - guest writes to the DSN bytes are rejected (no change), and
+ *  - VFIO_DEVICE_FEATURE_PCI_DSN can probe/set/get the presented serial.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+
+#include <linux/limits.h>
+#include <linux/pci_regs.h>
+#include <linux/vfio.h>
+
+#include <libvfio.h>
+
+#include "kselftest_harness.h"
+
+static const char *device_bdf;
+
+/* Walk the extended capability chain and return the DSN cap offset, or 0. */
+static u16 find_dsn_cap(struct vfio_pci_device *device)
+{
+	u16 pos = PCI_CFG_SPACE_SIZE;
+	int loops = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) /
+		    PCI_CAP_SIZEOF;
+
+	while (pos >= PCI_CFG_SPACE_SIZE && loops--) {
+		u32 header = vfio_pci_config_readl(device, pos);
+
+		if (!header)
+			break;
+
+		if (PCI_EXT_CAP_ID(header) == PCI_EXT_CAP_ID_DSN)
+			return pos;
+
+		pos = PCI_EXT_CAP_NEXT(header);
+	}
+
+	return 0;
+}
+
+/*
+ * Issue the DSN device feature.  @serial may be NULL for PROBE (no data is
+ * read or written in that case); for GET/SET it is required.
+ */
+static int dsn_feature(struct vfio_pci_device *device, u32 op, u64 *serial)
+{
+	u8 buf[sizeof(struct vfio_device_feature) +
+	       sizeof(struct vfio_device_feature_pci_dsn)] = {};
+	struct vfio_device_feature *feature = (void *)buf;
+	struct vfio_device_feature_pci_dsn *dsn = (void *)feature->data;
+
+	feature->argsz = sizeof(buf);
+	feature->flags = op | VFIO_DEVICE_FEATURE_PCI_DSN;
+
+	if ((op & VFIO_DEVICE_FEATURE_SET) && serial)
+		dsn->serial_number = *serial;
+
+	if (ioctl(device->fd, VFIO_DEVICE_FEATURE, feature))
+		return -errno;
+
+	if ((op & VFIO_DEVICE_FEATURE_GET) && serial)
+		*serial = dsn->serial_number;
+
+	return 0;
+}
+
+FIXTURE(vfio_pci_dsn_test) {
+	struct iommu *iommu;
+	struct vfio_pci_device *device;
+	u16 dsn_pos;
+};
+
+FIXTURE_SETUP(vfio_pci_dsn_test)
+{
+	self->iommu = iommu_init(default_iommu_mode);
+	self->device = vfio_pci_device_init(device_bdf, self->iommu);
+	self->dsn_pos = find_dsn_cap(self->device);
+}
+
+FIXTURE_TEARDOWN(vfio_pci_dsn_test)
+{
+	vfio_pci_device_cleanup(self->device);
+	iommu_cleanup(self->iommu);
+}
+
+/* The physical serial number must not be visible; reads must be zero. */
+TEST_F(vfio_pci_dsn_test, serial_scrubbed)
+{
+	if (!self->dsn_pos)
+		SKIP(return, "Device has no DSN capability\n");
+
+	ASSERT_EQ(0, vfio_pci_config_readl(self->device, self->dsn_pos + PCI_DSN_LOW_DW));
+	ASSERT_EQ(0, vfio_pci_config_readl(self->device, self->dsn_pos + PCI_DSN_HIGH_DW));
+
+	/* The capability header itself must still be present. */
+	ASSERT_EQ(PCI_EXT_CAP_ID_DSN,
+		  PCI_EXT_CAP_ID(vfio_pci_config_readl(self->device,
+						       self->dsn_pos)));
+}
+
+/* Guest writes to the DSN bytes must be ignored (read-only state). */
+TEST_F(vfio_pci_dsn_test, write_rejected)
+{
+	if (!self->dsn_pos)
+		SKIP(return, "Device has no DSN capability\n");
+
+	vfio_pci_config_writel(self->device, self->dsn_pos + PCI_DSN_LOW_DW, 0xdeadbeef);
+	vfio_pci_config_writel(self->device, self->dsn_pos + PCI_DSN_HIGH_DW, 0xcafef00d);
+
+	ASSERT_EQ(0, vfio_pci_config_readl(self->device, self->dsn_pos + PCI_DSN_LOW_DW));
+	ASSERT_EQ(0, vfio_pci_config_readl(self->device, self->dsn_pos + PCI_DSN_HIGH_DW));
+}
+
+/* PROBE must succeed iff the device has a DSN capability. */
+TEST_F(vfio_pci_dsn_test, probe)
+{
+	/* PROBE must include at least one supported op flag to pass. */
+	int ret = dsn_feature(self->device,
+			      VFIO_DEVICE_FEATURE_PROBE |
+			      VFIO_DEVICE_FEATURE_GET |
+			      VFIO_DEVICE_FEATURE_SET, NULL);
+
+	if (!self->dsn_pos)
+		ASSERT_EQ(-ENOTTY, ret);
+	else
+		ASSERT_EQ(0, ret);
+}
+
+/* SET then GET must round-trip, and the guest-visible bytes must match. */
+TEST_F(vfio_pci_dsn_test, set_get_roundtrip)
+{
+	u64 want = 0x0123456789abcdefULL;
+	u64 got = 0;
+
+	if (!self->dsn_pos)
+		SKIP(return, "Device has no DSN capability\n");
+
+	ASSERT_EQ(0, dsn_feature(self->device, VFIO_DEVICE_FEATURE_SET, &want));
+	ASSERT_EQ(0, dsn_feature(self->device, VFIO_DEVICE_FEATURE_GET, &got));
+	ASSERT_EQ(want, got);
+
+	ASSERT_EQ((u32)want,
+		  vfio_pci_config_readl(self->device, self->dsn_pos + PCI_DSN_LOW_DW));
+	ASSERT_EQ((u32)(want >> 32),
+		  vfio_pci_config_readl(self->device, self->dsn_pos + PCI_DSN_HIGH_DW));
+}
+
+/* SET twice; GET must return the latest value. */
+TEST_F(vfio_pci_dsn_test, set_twice)
+{
+	u64 first = 0x1111222233334444ULL;
+	u64 second = 0xaaaabbbbccccddddULL;
+	u64 got = 0;
+
+	if (!self->dsn_pos)
+		SKIP(return, "Device has no DSN capability\n");
+
+	ASSERT_EQ(0, dsn_feature(self->device, VFIO_DEVICE_FEATURE_SET, &first));
+	ASSERT_EQ(0, dsn_feature(self->device, VFIO_DEVICE_FEATURE_SET, &second));
+	ASSERT_EQ(0, dsn_feature(self->device, VFIO_DEVICE_FEATURE_GET, &got));
+	ASSERT_EQ(second, got);
+}
+
+/* The presented serial persists across a device reset (FLR/SBR). */
+TEST_F(vfio_pci_dsn_test, persists_across_reset)
+{
+	u64 want = 0x5555666677778888ULL;
+	u64 got = 0;
+
+	if (!self->dsn_pos)
+		SKIP(return, "Device has no DSN capability\n");
+	if (!(self->device->info.flags & VFIO_DEVICE_FLAGS_RESET))
+		SKIP(return, "Device does not support reset\n");
+
+	ASSERT_EQ(0, dsn_feature(self->device, VFIO_DEVICE_FEATURE_SET, &want));
+	vfio_pci_device_reset(self->device);
+	ASSERT_EQ(0, dsn_feature(self->device, VFIO_DEVICE_FEATURE_GET, &got));
+	ASSERT_EQ(want, got);
+}
+
+/* A short argsz must be rejected with -EINVAL. */
+TEST_F(vfio_pci_dsn_test, bad_argsz)
+{
+	struct vfio_device_feature feature = {
+		.argsz = sizeof(struct vfio_device_feature),
+		.flags = VFIO_DEVICE_FEATURE_GET | VFIO_DEVICE_FEATURE_PCI_DSN,
+	};
+
+	if (!self->dsn_pos)
+		SKIP(return, "Device has no DSN capability\n");
+
+	ASSERT_EQ(-1, ioctl(self->device->fd, VFIO_DEVICE_FEATURE, &feature));
+	ASSERT_EQ(EINVAL, errno);
+}
+
+int main(int argc, char *argv[])
+{
+	device_bdf = vfio_selftests_get_bdf(&argc, argv);
+	return test_harness_run(argc, argv);
+}

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC 1/3] vfio/pci: Virtualize and scrub Device Serial Number from guests
  2026-06-13 17:43 ` [PATCH RFC 1/3] vfio/pci: Virtualize and scrub Device Serial Number from guests Pranjal Arya
@ 2026-06-13 17:55   ` sashiko-bot
  0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-06-13 17:55 UTC (permalink / raw)
  To: Pranjal Arya; +Cc: linux-pci, kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing bounds check in `vfio_ecap_init()` and `vfio_cap_init()` allows malformed PCI capabilities to cause out-of-bounds memory accesses.
--

commit b6096a89941aa7c7c7c1394233c57ed4b01c16d6
Author: Pranjal Arya <pranjal.arya@oss.qualcomm.com>

vfio/pci: Virtualize and scrub Device Serial Number from guests

This commit virtualizes the PCIe Device Serial Number (DSN) capability in
vfio-pci to prevent guests from reading the persistent hardware serial number.
It adds a permission bits initializer for DSN and zeros out the serial number
in the virtualized config space during capability initialization.

> diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
> index a10ed733f0e3a..24dfeb43cb714 100644
> --- a/drivers/vfio/pci/vfio_pci_config.c
> +++ b/drivers/vfio/pci/vfio_pci_config.c

[ ... ]

> @@ -1702,6 +1729,18 @@ static int vfio_ecap_init(struct vfio_pci_core_device *vdev)
>  		if (ret)
>  			return ret;
>  
> +		/*
> +		 * Scrub the physical Device Serial Number from the
> +		 * virtualized config space so the guest cannot read the
> +		 * host device's unique identifier.  The capability is fully
> +		 * virtualized (see init_pci_ext_cap_dsn_perm()), so reads
> +		 * return this scrubbed value rather than hardware.  The user
> +		 * can present a chosen serial via VFIO_DEVICE_FEATURE_PCI_DSN.
> +		 */
> +		if (ecap == PCI_EXT_CAP_ID_DSN)
> +			memset(&vdev->vconfig[epos + PCI_DSN_LOW_DW], 0,
> +			       sizeof(__le64));

[Severity: High]
This is a pre-existing issue, but does this loop need to verify that the
capability length fits within the config space buffer before writing?

Looking at vfio_ecap_init(), the loop iterates using the hardware-provided
capability pointer (epos). If a device presents a DSN capability (which has
a length of 12) at an offset near the end of the config space (for example,
if epos is 4092 for a 4096-byte PCIe config space), the capability would
extend beyond pdev->cfg_size.

Since vconfig and map are dynamically allocated based on pdev->cfg_size,
would the newly added memset() write out-of-bounds into the kernel heap?

This new memset() shares the same lack of bounds checking as the existing
unconditional capability writes in vfio_ecap_init():

	memset(map + epos, ecap, len);

and similarly in vfio_cap_init():

	memset(map + pos, cap, len);

Could a malicious physical PCI device or compromised VF supply a crafted
capability list to exploit this?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260613-pcie_vfio-v1-0-09168188f3f2@oss.qualcomm.com?part=1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC 2/3] vfio/pci: Allow userspace to set a virtual Device Serial Number
  2026-06-13 17:43 ` [PATCH RFC 2/3] vfio/pci: Allow userspace to set a virtual Device Serial Number Pranjal Arya
@ 2026-06-13 17:58   ` sashiko-bot
  0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-06-13 17:58 UTC (permalink / raw)
  To: Pranjal Arya; +Cc: kvm, linux-pci

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] The VFIO_DEVICE_FEATURE_PCI_DSN ioctl can cause an out-of-bounds heap read or write on the `vdev->vconfig` buffer if a device exposes a DSN capability near the end of its PCIe configuration space.
- [Medium] UAPI documentation states `serial_number` is in little-endian wire order, but the implementation processes it as a host-endian `u64`.
- [Medium] The use of `WRITE_ONCE()` on the writer side does not prevent tearing because the concurrent reader side uses `memcpy()`, leading to a data race.
--

commit 519ac218356009252a82c7aa68a221467812de3f
Author: Pranjal Arya <pranjal.arya@oss.qualcomm.com>

vfio/pci: Allow userspace to set a virtual Device Serial Number

This patch adds a VFIO_DEVICE_FEATURE_PCI_DSN device feature that lets the
trusted userspace VMM GET or SET the 64-bit serial number presented in the
device's virtualized config space.

> diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
> index 24dfeb43cb714..60c19129c8145 100644
> --- a/drivers/vfio/pci/vfio_pci_config.c
> +++ b/drivers/vfio/pci/vfio_pci_config.c
> @@ -2078,3 +2078,62 @@ bool vfio_pci_core_range_intersect_range(loff_t buf_start, size_t buf_cnt,
[ ... ]
> +int vfio_pci_core_feature_dsn(struct vfio_pci_core_device *vdev, u32 flags,
> +			      void __user *arg, size_t argsz)
> +{
[ ... ]
> +	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DSN);
> +	if (!pos)
> +		return -ENOTTY;
> +
> +	ret = vfio_check_feature(flags, argsz,
> +				 VFIO_DEVICE_FEATURE_GET |
> +				 VFIO_DEVICE_FEATURE_SET,
> +				 sizeof(dsn));
> +	if (ret != 1)
> +		return ret;
> +
> +	vserial = (__le32 *)&vdev->vconfig[pos + PCI_DSN_LOW_DW];

[Severity: High]
Does this code risk an out-of-bounds heap read or write on vdev->vconfig?

pci_find_ext_capability() only guarantees that the 4-byte capability header
fits within pdev->cfg_size. If a device exposes a DSN capability near the
end of its PCIe configuration space (for example, at offset 4092), pos will
be 4092.

Since vdev->vconfig is allocated with exactly pdev->cfg_size bytes, accessing
pos + PCI_DSN_LOW_DW (offset 4) will calculate a pointer completely out of
bounds, causing the subsequent operations to access adjacent kernel heap memory.

> +
> +	if (flags & VFIO_DEVICE_FEATURE_SET) {
> +		if (copy_from_user(&dsn, arg, sizeof(dsn)))
> +			return -EFAULT;
> +
> +		/*
> +		 * The config-space read path (vfio_default_config_read())
> +		 * does not hold a lock, and a guest reads the DSN as two
> +		 * 32-bit dwords.  Store each dword with WRITE_ONCE() so a
> +		 * concurrent guest read observes a consistent dword; a guest
> +		 * reading the two halves around this update may see an
> +		 * old/new mix, exactly as hardware may tear a 64-bit read of
> +		 * a register pair.  This matches the DSN's read-only,
> +		 * advisory nature.  Serializing concurrent SET callers is the
> +		 * userspace VMM's responsibility.
> +		 */
> +		WRITE_ONCE(vserial[0], cpu_to_le32(lower_32_bits(dsn.serial_number)));
> +		WRITE_ONCE(vserial[1], cpu_to_le32(upper_32_bits(dsn.serial_number)));

[Severity: Medium]
Does using WRITE_ONCE() here actually prevent torn reads by the guest?

The comments state this is to ensure a concurrent guest read observes a
consistent dword. However, the guest config-space read path in
vfio_default_config_read() uses memcpy(), which performs plain, non-atomic
memory accesses.

Because the compiler and processor are free to split the memcpy() load into
byte-sized operations, WRITE_ONCE() on the writer side does not guarantee
that the reader will observe an atomic 32-bit read.

> +		return 0;
> +	}
[ ... ]
> diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
> index 5de618a3a5eee..e5b8dfd3833f6 100644
> --- a/include/uapi/linux/vfio.h
> +++ b/include/uapi/linux/vfio.h
> @@ -1511,6 +1511,24 @@ struct vfio_device_feature_bus_master {
[ ... ]
> +/**
> + * Upon VFIO_DEVICE_FEATURE_SET, set the PCIe Device Serial Number (DSN)
> + * presented to the user (guest) in the device's virtualized config space.
> + * By default vfio-pci scrubs the physical DSN to zero so the host device's
> + * unique identifier is not leaked; this feature lets the hypervisor present
> + * a chosen, per-VM synthetic serial instead (for example a stable but
> + * non-host-identifying value for migration).
> + *
> + * Upon VFIO_DEVICE_FEATURE_GET, read back the currently presented serial.
> + *
> + * The feature is only available for devices that expose a DSN capability.
> + * serial_number is the 64-bit serial in little-endian wire order.
> + */
> +struct vfio_device_feature_pci_dsn {
> +	__aligned_u64 serial_number;
> +};

[Severity: Medium]
Is there an endianness mismatch between this documentation and the
implementation?

The documentation states serial_number is the 64-bit serial in little-endian
wire order. However, vfio_pci_core_feature_dsn() treats it as a host-endian
value when extracting halves:

    WRITE_ONCE(vserial[0], cpu_to_le32(lower_32_bits(dsn.serial_number)));

If a userspace program on a big-endian system follows the documentation and
provides a pre-formatted little-endian value, the kernel will interpret it as
a big-endian integer, incorrectly extract the halves, and store garbled bytes
into the virtual config space.

Should the documentation be updated to indicate a host-endian 64-bit integer,
or should the code be changed to expect an __le64 type?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260613-pcie_vfio-v1-0-09168188f3f2@oss.qualcomm.com?part=2

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC 3/3] selftests/vfio: Add PCIe Device Serial Number test
  2026-06-13 17:43 ` [PATCH RFC 3/3] selftests/vfio: Add PCIe Device Serial Number test Pranjal Arya
@ 2026-06-13 18:01   ` sashiko-bot
  0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-06-13 18:01 UTC (permalink / raw)
  To: Pranjal Arya; +Cc: linux-pci, kvm

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [Medium] Endianness mismatch in PCI configuration space reads leading to test failures on big-endian architectures.
- [Medium] Type punning from a byte array to structs with stricter alignment requirements violates strict aliasing and alignment rules.
- [Low] Capability walker fails to break on unpopulated extended configuration space (`0xffffffff`).

Pre-existing issues:
- [Critical] Missing bounds checking when parsing PCI extended capabilities causes heap buffer overflows.
--

commit 83546a8f398b5cb4fdb341d52a4a665cb8639619
Author: Pranjal Arya <pranjal.arya@oss.qualcomm.com>

selftests/vfio: Add PCIe Device Serial Number test

This patch adds a selftest to verify the vfio-pci DSN handling, ensuring that
the serial number is scrubbed by default and that the VFIO_DEVICE_FEATURE_PCI_DSN
feature correctly probes, sets, and gets the presented serial.

> diff --git a/tools/testing/selftests/vfio/vfio_pci_dsn_test.c b/tools/testing/selftests/vfio/vfio_pci_dsn_test.c
> new file mode 100644
> index 0000000000000..d7652ad725f4e
> --- /dev/null
> +++ b/tools/testing/selftests/vfio/vfio_pci_dsn_test.c
> @@ -0,0 +1,206 @@
[ ... ]
> +/* Walk the extended capability chain and return the DSN cap offset, or 0. */
> +static u16 find_dsn_cap(struct vfio_pci_device *device)
> +{
> +	u16 pos = PCI_CFG_SPACE_SIZE;
> +	int loops = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) /
> +		    PCI_CAP_SIZEOF;
> +
> +	while (pos >= PCI_CFG_SPACE_SIZE && loops--) {
> +		u32 header = vfio_pci_config_readl(device, pos);

[Severity: Medium]
Since vfio_pci_config_readl() reads raw little-endian bytes directly from the
device, will reading them into a host-endian u32 without a conversion like
le32toh() break capability header parsing on big-endian architectures?

> +
> +		if (!header)

[Severity: Low]
When a device implements no further PCIe extended capabilities, the config
header typically reads as 0xffffffff.

Does checking only for 0 miss the standard 0xffffffff value, causing the loop
to continuously re-read offset 0xffc and wastefully execute ioctls until the
safety counter expires?

> +			break;
> +
> +		if (PCI_EXT_CAP_ID(header) == PCI_EXT_CAP_ID_DSN)
> +			return pos;
> +
> +		pos = PCI_EXT_CAP_NEXT(header);
> +	}
> +
> +	return 0;
> +}
[ ... ]
> +static int dsn_feature(struct vfio_pci_device *device, u32 op, u64 *serial)
> +{
> +	u8 buf[sizeof(struct vfio_device_feature) +
> +	       sizeof(struct vfio_device_feature_pci_dsn)] = {};

[Severity: Medium]
Does this byte array guarantee only 1-byte alignment?

Because tools/ is compiled with standard -fstrict-aliasing, casting this byte
array to structs with stricter alignment requirements could violate strict
aliasing and alignment rules.

> +	struct vfio_device_feature *feature = (void *)buf;
> +	struct vfio_device_feature_pci_dsn *dsn = (void *)feature->data;
> +
> +	feature->argsz = sizeof(buf);
> +	feature->flags = op | VFIO_DEVICE_FEATURE_PCI_DSN;
> +
> +	if ((op & VFIO_DEVICE_FEATURE_SET) && serial)
> +		dsn->serial_number = *serial;

[Severity: Medium]
Will dereferencing the pointer to this 8-byte aligned struct member from the
1-byte aligned buf[] cause unaligned memory access faults on strict
architectures?

> +
> +	if (ioctl(device->fd, VFIO_DEVICE_FEATURE, feature))
[ ... ]
> +/* SET then GET must round-trip, and the guest-visible bytes must match. */
> +TEST_F(vfio_pci_dsn_test, set_get_roundtrip)
> +{
> +	u64 want = 0x0123456789abcdefULL;
> +	u64 got = 0;
> +
> +	if (!self->dsn_pos)
> +		SKIP(return, "Device has no DSN capability\n");
> +
> +	ASSERT_EQ(0, dsn_feature(self->device, VFIO_DEVICE_FEATURE_SET, &want));
> +	ASSERT_EQ(0, dsn_feature(self->device, VFIO_DEVICE_FEATURE_GET, &got));
> +	ASSERT_EQ(want, got);
> +
> +	ASSERT_EQ((u32)want,
> +		  vfio_pci_config_readl(self->device, self->dsn_pos + PCI_DSN_LOW_DW));

[Severity: Medium]
Will comparing a host-endian expected value against raw little-endian bytes
read by vfio_pci_config_readl() cause false test failures on big-endian
architectures?


[Severity: Critical]
This is a pre-existing issue, but I noticed missing bounds checking when
parsing PCI extended capabilities that could cause heap buffer overflows.

Looking at vfio_ecap_init() in drivers/vfio/pci/vfio_pci_config.c:

    memset(map + epos, ecap, len);

This writes ecap bytes into map based on an unverified capability length, which
could lead to an out-of-bounds write onto the kernel heap if a malicious
emulated or physical device places a capability near the end of the extended
config space (so that epos + len exceeds pdev->cfg_size).

Additionally, looking at vfio_pci_core_feature_dsn() in
drivers/vfio/pci/vfio_pci_config.c:

    WRITE_ONCE(vserial[0], cpu_to_le32(lower_32_bits(dsn.serial_number)));

Could this directly write 8 bytes to vdev->vconfig at pos + 4 without verifying
that pos + 12 <= pdev->cfg_size, similarly writing user-controlled bytes out of
bounds?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260613-pcie_vfio-v1-0-09168188f3f2@oss.qualcomm.com?part=3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number
  2026-06-13 17:43 [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number Pranjal Arya
                   ` (2 preceding siblings ...)
  2026-06-13 17:43 ` [PATCH RFC 3/3] selftests/vfio: Add PCIe Device Serial Number test Pranjal Arya
@ 2026-06-13 18:56 ` Alex Williamson
  2026-06-13 20:35 ` Pranjal Shrivastava
  4 siblings, 0 replies; 9+ messages in thread
From: Alex Williamson @ 2026-06-13 18:56 UTC (permalink / raw)
  To: Pranjal Arya, Bjorn Helgaas, David Matlack, Shuah Khan
  Cc: linux-arm-msm, kvm, linux-kernel, linux-pci, linux-kselftest,
	Pranjal Shrivastava, Manivannan Sadhasivam



On Sat, Jun 13, 2026, at 11:43 AM, Pranjal Arya wrote:
> vfio-pci has no perm_bits entry for the PCIe Device Serial Number (DSN)
> Extended Capability, so guest reads of the serial
> number currently fall through to the physical device.  The DSN is a
> unique, persistent hardware serial number that identifies the physical
> component (the functions of a Multi-Function Device report the same
> value; Root Complex integrated Endpoints may implement it independently),
> so exposing it lets a guest fingerprint the host hardware and correlate
> it across VMs.  For multi-tenant passthrough this is an unnecessary
> host-identifier leak.

This sounds like a userspace problem, QEMU can virtualize the capability and manipulate it as it sees fit.  Thanks,

Alex

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number
  2026-06-13 17:43 [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number Pranjal Arya
                   ` (3 preceding siblings ...)
  2026-06-13 18:56 ` [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number Alex Williamson
@ 2026-06-13 20:35 ` Pranjal Shrivastava
  4 siblings, 0 replies; 9+ messages in thread
From: Pranjal Shrivastava @ 2026-06-13 20:35 UTC (permalink / raw)
  To: Pranjal Arya
  Cc: Alex Williamson, Bjorn Helgaas, David Matlack, Shuah Khan,
	linux-arm-msm, kvm, linux-kernel, linux-pci, linux-kselftest,
	Manivannan Sadhasivam

On Sat, Jun 13, 2026 at 11:13:35PM +0530, Pranjal Arya wrote:

Hi Pranjal,

> vfio-pci has no perm_bits entry for the PCIe Device Serial Number (DSN)
> Extended Capability, so guest reads of the serial
> number currently fall through to the physical device.  The DSN is a
> unique, persistent hardware serial number that identifies the physical
> component (the functions of a Multi-Function Device report the same
> value; Root Complex integrated Endpoints may implement it independently),
> so exposing it lets a guest fingerprint the host hardware and correlate
> it across VMs.  For multi-tenant passthrough this is an unnecessary
> host-identifier leak.
>

+ 1 to what Alex said here, QEMU / VMM should be able to trap and present
the desired values here, we shouldn't need this in the vconfig. Thus, I
believe this is better suited to QEMU (maybe this should be a patch to
QEMU?)

> 
> Signed-off-by: Pranjal Arya <pranjal.arya@oss.qualcomm.com>
> ---
> Pranjal Arya (3):
>       vfio/pci: Virtualize and scrub Device Serial Number from guests
>       vfio/pci: Allow userspace to set a virtual Device Serial Number
>       selftests/vfio: Add PCIe Device Serial Number test
> 
>  MAINTAINERS                                      |   6 +
>  drivers/vfio/pci/vfio_pci_config.c               |  98 +++++++++++
>  drivers/vfio/pci/vfio_pci_core.c                 |   2 +
>  drivers/vfio/pci/vfio_pci_priv.h                 |   2 +
>  include/uapi/linux/pci_regs.h                    |   5 +
>  include/uapi/linux/vfio.h                        |  18 ++
>  tools/testing/selftests/vfio/Makefile            |   1 +
>  tools/testing/selftests/vfio/vfio_pci_dsn_test.c | 206 +++++++++++++++++++++++
>  8 files changed, 338 insertions(+)
> ---
> base-commit: c425609d6ac4012c8bbf01ec2e10e801b1923a7b
> change-id: 20260613-pcie_vfio-48506602ec6a

A few minor things, we don't use change-id upstream and no need to add a
MAINTAINERS entry per test, we already have an entry to maintain
tools/testing/selftests/vfio.

Thanks,
Praan

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-06-13 20:35 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-13 17:43 [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number Pranjal Arya
2026-06-13 17:43 ` [PATCH RFC 1/3] vfio/pci: Virtualize and scrub Device Serial Number from guests Pranjal Arya
2026-06-13 17:55   ` sashiko-bot
2026-06-13 17:43 ` [PATCH RFC 2/3] vfio/pci: Allow userspace to set a virtual Device Serial Number Pranjal Arya
2026-06-13 17:58   ` sashiko-bot
2026-06-13 17:43 ` [PATCH RFC 3/3] selftests/vfio: Add PCIe Device Serial Number test Pranjal Arya
2026-06-13 18:01   ` sashiko-bot
2026-06-13 18:56 ` [PATCH RFC 0/3] vfio/pci: Hide and optionally override the PCIe Device Serial Number Alex Williamson
2026-06-13 20:35 ` Pranjal Shrivastava

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.