Files
vfio-native/patches/README.md
T

107 lines
7.4 KiB
Markdown

# Patchsets, by the detection each one clears
Every patch here is grouped by the VMAware check it targets, so a patchset can be taken or left
on its own. Apply from the relevant source root with `patch -p1 < <file>`.
## KVM - `kvm/`
Built against kernel 7.2.x. Builds as `arch/x86/kvm` only, about five minutes; no full kernel
build is needed. See `packaging/` for a PKGBUILD that does it and keeps it rebuilt.
| Patch | Clears | What it does |
| --- | --- | --- |
| `0001-KVM-SVM-intercept-GP-when-guest-EFER.SVME-is-clear` | `SVM_EXCEPTIONS` | Closes a `FIXME` KVM already carries: a CPL3 SVM instruction faults `#GP` where hardware gives `#UD`. |
| `0002-KVM-x86-emulator-UD-not-GP-for-VMCALL-at-CPL-0` | `KVM_INTERCEPTION` | Adds `PrivUD` so `VMCALL` at CPL>0 raises `#UD` like hardware. |
| `0003-KVM-x86-UD-for-KVM-hypercalls-issued-at-CPL-0` | `KVM_INTERCEPTION` | A CPL>0 hypercall raised no exception at all; now raises `#UD`. |
| `0004-KVM-SVM-intercept-ICEBP-and-skip-it-before-injecting-its-DB` | `DBVM` | SVM re-injected the `ICEBP` `#DB` with RIP still on the `F1` byte; VMX and hardware report the next instruction. |
| `0005-KVM-selftests-verify-ICEBP-DB-reports-RIP-past-the-ICEBP` | - | The selftest for 0004: fails on unpatched SVM, passes with it. |
| `EXPERIMENTAL-0006-runtime-cpuid-passthrough` | `TIMER` | Drops CPUID and RDPRU interception on a 1:1-pinned vCPU and reprograms the AMD Processor Name String MSRs so raw `CPUID` still returns the declared brand. Opt-in via the `cpuid_passthrough` module parameter. |
**0002 and 0003 are a pair.** Either alone leaves `KVM_INTERCEPTION` standing, because the check
tries two stubs and only reports the first one that misbehaves.
The first five are written to be acceptable upstream: they make KVM match the architecture rather
than add anything on top of it, each carries its rationale in the commit message, and all four
pass `checkpatch.pl --strict`. `0000-cover-letter.txt` is the series cover letter. They
have been tested on AMD only; 0002 and 0003 are vendor-neutral code and the Intel reasoning is in
the cover letter.
**`EXPERIMENTAL-0006` is built into the `vfio-native-kvm-dkms` package but off by default.** It
removes the cost the `TIMER` instruction-latency detector measures, and with it the guest reads
raw host CPUID, so it applies itself only to vCPU threads confined to exactly one CPU and must be
enabled through the `cpuid_passthrough` module parameter after the guest has booted.
`docs/ANALYSIS.md` has the measurements and the constraints.
## QEMU - `qemu/`
Against QEMU v11.1.2. Apply in numeric order.
| Patch | Clears |
| --- | --- |
| `01-firmware` | `FIRMWARE` - ACPI link-device names, `PNP0A06` stubs, FADT C-state latencies |
| `02-disk-identity` | `VIRTUAL_DISK`, `DISK_SERIAL` - `QEMU HARDDISK`, empty serials, SCSI inquiry strings |
| `03-pci-ids` | `PCI_VENDOR`, `DEVICES` - Red Hat/QEMU vendor and subsystem IDs, ICH9 layout |
| `04-fw-cfg` | `QEMU_FW_CFG` - the fw_cfg device signature |
| `05-usb-identity` | `QEMU_USB` - USB HID descriptor strings, and the usb-net CDC/RNDIS device-identity strings (keeps the `0525:a4a1` CDC id so generic CDC-ECM drivers still bind it) |
| `06-audio` | `DEVICES` - HDA codec and controller identity |
| `07-edid` | none. Carried for other detectors; VMAware does not read EDID. |
| `08-cpu-misc` | none. CPU feature plumbing and one upstream backport. |
| `09-firmware-chain` | `FIRMWARE` - the DSDT links current VMAware added after `01-firmware` |
| `10-smbios` | `CTYPE`, `SMBIOS_VM_BIT`, `FIRMWARE` - what QEMU's synthesised SMBIOS leaks: chassis type Other, the type 0 VM bit, `pc-q35` default strings; adds `-smbios type=3,chassis-type=N` |
| `11-macos-cpu-hotplug` | `FIRMWARE` - re-adds the `\_SB.CPUS` CPU objects macOS needs, with the CPU-hotplug I/O base `0x0CD8` hidden from the scanner (renamed `_UID`, `Add()`-split OperationRegion base) rather than removed |
The numbered patches are the default series and score 0/85 on both VMAware HEAD and v2.8.1.
`03-pci-ids` scopes the virtio subsystem-id change so OVMF still binds virtio (its generic default
goes to Intel/0, virtio devices keep the Red Hat subsystem ids their drivers and OVMF expect). It
also leaves the ICH9 SATA controller at its stock slot `1f.2`: OVMF locates the q35 AHCI there, so
moving it broke first-boot for SATA-booted UEFI guests (macOS fell through to PXE) while buying
nothing for the score - the dummy-SATA FIRMWARE tell needs both the `D0FA` name and `_ADR 0x1F0002`,
and device 31's functions emit neither. See `docs/ANALYSIS.md`.
`11-macos-cpu-hotplug` makes the series universal: macOS boots (it needs the `\_SB.CPUS.Cxxx`
objects from `build_cpus_aml`) and both VMAware builds still read bare metal, with no opt-in. The
block's only tell, the `0x0CD8` CPU-hotplug port that v2.8.1 FIRMWARE byte-matches, is removed at
the AML level without moving the port, so the same series boots Windows and Linux unchanged. The
earlier opt-in split and the relocate-the-base approach are in "Approaches tried and rejected".
Apply in numeric order, then build with the prefix set to `/opt` so the system QEMU package is left
alone:
```sh
for p in qemu/[0-9][0-9]-*.patch; do patch -p1 < "$p"; done
./configure --prefix=/opt/qemu-native --target-list=x86_64-softmmu
ninja -C build && ninja -C build install
```
## Approaches tried and rejected - kept so they are not re-derived
| Approach | Result |
| --- | --- |
| Patched OVMF firmware (`edk2`) | Builds, then hangs before console init at 100% CPU, cause undiagnosed. Stock OVMF is fine and costs only the boot-logo warning. |
| TSC compensation for `TIMER` (BetterTiming) | No detection change, 6x slower boot. |
| CPUID leaf override (Hypervisor-Phantom) | Halved the timing signature, still detected, and *added* a `SINGLE_STEP` detection. |
| Clearing `INTERCEPT_CPUID` outright | Guest never boots. |
| Intercept clearing, minimal hypercall | Triple fault, or no effect. |
| Opt-in macOS CPU block (`optional/macos-cpu-hotplug`) | Worked but split the series in two; a macOS-capable build scored 2/85 on v2.8.1. Folded into `11` instead. |
| Relocating the CPU-hotplug I/O base off `0x0CD8` | Clears the scanner but hangs every SMM/OVMF guest (macOS spins 10 cores at boot, Windows too): OVMF hardcodes `0x0CD8` in `OvmfPkg` and reads the register block directly. `11` keeps the port and hides only the AML operand. |
`TIMER` has two detectors that OR together. The exception-latency one passes on stock KVM once it
is measured the way VMAware measures it; the instruction-latency one is removable with
`EXPERIMENTAL-0006`. `docs/ANALYSIS.md` has the measurements, including a direct reproduction of
both in `bench/timerprobe.c`.
## Identity values in these patches
Several patches carry a concrete make and model because no real machine leaves the field blank.
Every one of them is a placeholder. Change them before you use this, or a detector gains a
fingerprint shared by everyone who ran the same patch series.
| Where | Value | Replace with |
| --- | --- | --- |
| `02-disk-identity` | disk serial `S0123456789ABCD` | set `<serial>` on the disk in the domain XML; this fallback then never runs |
| `02-disk-identity` | disk and optical drive model strings | a drive you actually own, from `lsblk -o NAME,MODEL` |
| `07-edid` | monitor vendor and model | your own panel, from `edid-decode < /sys/class/drm/*/edid` |
The SMBIOS values are not patched into QEMU at all - they are domain XML, taken from a real
machine with `dmidecode`. Change every serial there too.