Files
qemu-spoof/patches/0018-pci-subsystem-id.patch
T

53 lines
2.5 KiB
Diff

qemu-spoof: OEM-brand emulated PCI subsystem ids (realize-time)
QEMU stamps a constant subsystem id (default 1b36:1100) on every emulated PCI
device -- a fleet fingerprint. The subsystem id is not used for guest driver
binding, so override it at realize time with an OEM-branded SVID/SSID (chipset
vendor + per-role device id) for non-bridge devices. Red Hat/virtio (0x1af4) is
skipped: legacy-virtio encodes the device type in the subsystem id, so changing
it would break the guest driver (virtio is de-fingerprinted by device choice
instead). vfio passthrough overwrites this with the real hardware SSID afterwards.
This is the realize-time override path the deferred 0018 note called for; it does
NOT touch vendor/device ids (those ARE driver-binding and would break drivers).
Inert unless a spoof-seed is set.
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 2c3657d..e3da2ab 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -23,6 +23,7 @@
*/
#include "qemu/osdep.h"
+#include "hw/misc/spoof.h"
#include "qemu/datadir.h"
#include "qemu/units.h"
#include "hw/core/irq.h"
@@ -1417,6 +1418,27 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev,
assert(!pc->subsystem_vendor_id);
assert(!pc->subsystem_id);
}
+
+ /*
+ * qemu-spoof: OEM-brand the subsystem id of emulated devices. Real boards
+ * carry the vendor's SSID; QEMU stamps a constant 1b36:1100 default on every
+ * device, which is itself a fleet fingerprint. The subsystem id does not take
+ * part in driver binding, so this is safe -- EXCEPT for Red Hat/virtio
+ * (0x1af4), where legacy-virtio encodes the device type in the subsystem id;
+ * skip those (virtio is de-fingerprinted by device choice, not id spoofing).
+ * vfio passthrough overwrites this later with the real hardware SSID. Inert
+ * unless a spoof-seed is set.
+ */
+ if (spoof_enabled() && !is_bridge &&
+ pci_get_word(pci_dev->config + PCI_VENDOR_ID) != 0x1af4) {
+ const char *role = object_get_typename(OBJECT(pci_dev));
+ pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
+ spoof_pci_subvendor(
+ pci_get_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID)));
+ pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
+ spoof_pci_subdevice(role,
+ pci_get_word(pci_dev->config + PCI_SUBSYSTEM_ID)));
+ }
pci_init_cmask(pci_dev);
pci_init_wmask(pci_dev);
pci_init_w1cmask(pci_dev);