3268fe11e1
Override the qemu-nvme controller vendor:device (Red Hat 1b36:0010) to a real NVMe vendor matched to the spoofed model brand (Samsung/WD/Kioxia/Kingston/Intel/SMI/ hynix/Micron/Phison), with a coherent subsystem. Safe: NVMe binds by class code, not id, and this runs before nvme_init_ctrl so the IDENTIFY vid/ssvid stay aligned. virtio/GPU vendor:device untouched (load-bearing). Inert without a seed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
70 lines
3.6 KiB
Diff
70 lines
3.6 KiB
Diff
qemu-spoof: OEM-brand emulated PCI subsystem ids + class-bound nvme vendor:device
|
|
|
|
Realize-time overrides in do_pci_register_device (inert without a spoof-seed):
|
|
1. Subsystem id (SVID/SSID) of every non-bridge emulated device -> an OEM-branded
|
|
value. QEMU stamps a constant 1b36:1100 on all of them (a fleet fingerprint); the
|
|
subsystem id is not used for driver binding so this is safe. Red Hat/virtio
|
|
(0x1af4) is skipped -- legacy-virtio encodes the device type in the subsystem id.
|
|
2. The qemu-nvme controller (1b36:0010) vendor:device -> the real vendor:device of
|
|
the spoofed NVMe model brand (Samsung/WD/Kioxia/...), with a matching subsystem.
|
|
Safe because NVMe binds by class code, not id; runs before nvme_init_ctrl so the
|
|
IDENTIFY vid/ssvid stay coherent. virtio/GPU vendor:device are NOT touched (their
|
|
id IS the driver-binding contract). vfio passthrough overwrites with real hw ids.
|
|
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
|
|
index 2c3657d..c6eb0ef 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,44 @@ 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)));
|
|
+ }
|
|
+ /*
|
|
+ * qemu-spoof: class-bound device ids may be set to a REAL vendor:device safely,
|
|
+ * because the guest binds these by class code, not by id. qemu-nvme (Red Hat
|
|
+ * 1b36:0010) -> the vendor:device of the spoofed NVMe model's brand, with a
|
|
+ * matching subsystem (a real NVMe controller's SSVID equals its VID). This runs
|
|
+ * before nvme_init_ctrl, so the NVMe IDENTIFY vid/ssvid stay coherent. virtio /
|
|
+ * GPU ids are NOT touched here (their id IS the driver-binding contract).
|
|
+ */
|
|
+ if (spoof_enabled() &&
|
|
+ !strcmp(object_get_typename(OBJECT(pci_dev)), "nvme")) {
|
|
+ uint16_t vid = spoof_nvme_pci_vendor(pci_get_word(pci_dev->config + PCI_VENDOR_ID));
|
|
+ uint16_t did = spoof_nvme_pci_device(pci_get_word(pci_dev->config + PCI_DEVICE_ID));
|
|
+ pci_config_set_vendor_id(pci_dev->config, vid);
|
|
+ pci_config_set_device_id(pci_dev->config, did);
|
|
+ pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, vid);
|
|
+ pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, did);
|
|
+ }
|
|
pci_init_cmask(pci_dev);
|
|
pci_init_wmask(pci_dev);
|
|
pci_init_w1cmask(pci_dev);
|