[PATCH 00/25] KVM/arm64: VM configuration enforcement

Marc Zyngier maz at kernel.org
Mon Jan 22 12:18:27 PST 2024


Until recently, implementing a new feature in KVM was a matter of
looking at the CPU capability, and enabling the feature if it was
present. Very little effort was put into producing a configuration
that was independent of the host.

That was until we made the ID registers writable. Now, userspace can
configure a VM with an expected set of features, and relies on the
hypervisor to provide the corresponding architectural behaviour
(within the limits of what the architecture can actually enforce, more
on that later). Unfortunately, this last point has so far been left

Enforcing these constraints is important:

- VMs need to migrate between hosts that implement different feature
  sets. Allowing the guest to crate state on one system, and then to
  crash on another, is not an acceptable outcome. Yes, the SW was
  buggy, but it is the migration that broke it, and the hypervisor is
  at fault. Not handling this correctly also has the potential to
  create covert channels, something that I'm sure cloud vendors are
  really eager to put in production.

- Making sure that an unadvertised feature UNDEFs is a way to limit
  unexpected behaviours in an unsuspecting hypervisor. Specially when
  the architecture is as hostile to SW as this one.

- Honouring the VM configuration allows the KVM support to be phased,
  unless we want to mandate full NV support for everything right now.

This patch series aims to plug a number of the existing holes by
providing some basic mechanisms:

(1) add a way to easily parse the guest's ID registers and work out
    whether a particular level of support is advertised. This is
    provided as a small set of basic accessors that simply return a
    boolean indicating whether the supporting condition is satisfied.

(2) offer a way to enforce the effective values of the system
    registers backed by the VNCR page, even if the guest can write
    whatever it sees fit there. This is done by maintaining a set of
    RES0/RES1 masks computed from the guest's feature set, and these
    masks applied on each access to the in-memory register.

(3) provide a way to force a system register to UNDEF if there is a
    FGT associated with it. These so-called 'Fine-Grained UNDEF' bits
    shadow the FGT and are used to route the resulting exception.

Under the hood, this results in a number of significant changes: the
NV trap handling xarray becomes the basic data structure for handling
traps, even in non-NV configurations, and there is a number of new
data structures to manage the effective state. Oh, and we get some
more debugfs crap (which I'm not necessarily keen on merging).

A lot of effort has been put into computing the configuration only
once and rely on shadow data to enforce the desired behaviour.

Note that not all the possible configurations are handled:

- the surface is pretty large, and I have only tried to come up with
  significant *examples* of how things could be done. There is tons of
  additional work to be done beyond these patches.

- the architecture doesn't always allow some features to be completely
  hidden (any register backed by VNCR is always 'visible' if present
  on the host).

I expect that /some/ of this work could make it into 6.9 and be used
by any new feature added to KVM from that point onwards.

This series is based on v6.8-rc1 plus my E2H0 series, and is a prefix
for the rest of the NV series.

Marc Zyngier (25):
  arm64: sysreg: Add missing ID_AA64ISAR[13]_EL1 fields and variants
  KVM: arm64: Add feature checking helpers
  KVM: arm64: nv: Add sanitising to VNCR-backed sysregs
  KVM: arm64: nv: Add sanitising to EL2 configuration registers
  KVM: arm64: nv: Add sanitising to VNCR-backed FGT sysregs
  KVM: arm64: nv: Add sanitising to VNCR-backed HCRX_EL2
  KVM: arm64: nv: Drop sanitised_sys_reg() helper
  KVM: arm64: Unify HDFG[WR]TR_GROUP FGT identifiers
  KVM: arm64: nv: Correctly handle negative polarity FGTs
  KVM: arm64: nv: Turn encoding ranges into discrete XArray stores
  KVM: arm64: Drop the requirement for XARRAY_MULTI
  KVM: arm64: nv: Move system instructions to their own sys_reg_desc
    array
  KVM: arm64: Always populate the trap configuration xarray
  KVM: arm64: Register AArch64 system register entries with the sysreg
    xarray
  KVM: arm64: Use the xarray as the primary sysreg/sysinsn walker
  KVM: arm64: Rename __check_nv_sr_forward() to triage_sysreg_trap()
  KVM: arm64: Add Fine-Grained UNDEF tracking information
  KVM: arm64: Propagate and handle Fine-Grained UNDEF bits
  KVM: arm64: Move existing feature disabling over to FGU infrastructure
  KVM: arm64: Streamline save/restore of HFG[RW]TR_EL2
  KVM: arm64: Make TLBI OS/Range UNDEF if not advertised to the guest
  KVM: arm64: Make PIR{,E0}_EL1 UNDEF if S1PIE is not advertised to the
    guest
  KVM: arm64: Make AMU sysreg UNDEF if FEAT_AMU is not advertised to the
    guest
  KVM: arm64: Make FEAT_MOPS UNDEF if not advertised to the guest
  KVM: arm64: Add debugfs file for guest's ID registers

 arch/arm64/include/asm/kvm_arm.h           |   4 +-
 arch/arm64/include/asm/kvm_host.h          | 110 +++++++++
 arch/arm64/include/asm/kvm_nested.h        |   1 -
 arch/arm64/kvm/Kconfig                     |   1 -
 arch/arm64/kvm/arm.c                       |   7 +
 arch/arm64/kvm/emulate-nested.c            | 209 ++++++++++++----
 arch/arm64/kvm/hyp/include/hyp/switch.h    | 130 +++++-----
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h |  15 +-
 arch/arm64/kvm/nested.c                    | 265 ++++++++++++++++++++-
 arch/arm64/kvm/sys_regs.c                  | 224 ++++++++++++++---
 arch/arm64/kvm/sys_regs.h                  |   2 +
 arch/arm64/tools/sysreg                    |   8 +-
 12 files changed, 824 insertions(+), 152 deletions(-)

-- 
2.39.2




More information about the linux-arm-kernel mailing list