KVM: selftests: Add a shameful hack to preserve/clobber GPRs across ucall
authorSean Christopherson <seanjc@google.com>
Sat, 29 Jul 2023 00:36:12 +0000 (17:36 -0700)
committerSean Christopherson <seanjc@google.com>
Wed, 2 Aug 2023 21:41:59 +0000 (14:41 -0700)
commit6783ca4105a75d1ba4f89b13cef1bc1f677c41e5
tree02b27b6f26530cbf8b48046b297e84747ef6f1df
parentb145c58d95fff280c2726d0024005ae0a4ec378d
KVM: selftests: Add a shameful hack to preserve/clobber GPRs across ucall

Preserve or clobber all GPRs (except RIP and RSP, as they're saved and
restored via the VMCS) when performing a ucall on x86 to fudge around a
horrific long-standing bug in selftests' nested VMX support where L2's
GPRs are not preserved across a nested VM-Exit.  I.e. if a test triggers a
nested VM-Exit to L1 in response to a ucall, e.g. GUEST_SYNC(), then L2's
GPR state can be corrupted.

The issues manifests as an unexpected #GP in clear_bit() when running the
hyperv_evmcs test due to RBX being used to track the ucall object, and RBX
being clobbered by the nested VM-Exit.  The problematic hyperv_evmcs
testcase is where L0 (test's host userspace) injects an NMI in response to
GUEST_SYNC(8) from L2, but the bug could "randomly" manifest in any test
that induces a nested VM-Exit from L0.  The bug hasn't caused failures in
the past due to sheer dumb luck.

The obvious fix is to rework the nVMX helpers to save/restore L2 GPRs
across VM-Exit and VM-Enter, but that is a much bigger task and carries
its own risks, e.g. nSVM does save/restore GPRs, but not in a thread-safe
manner, and there is a _lot_ of cleanup that can be done to unify code
for doing VM-Enter on nVMX, nSVM, and eVMCS.

Link: https://lore.kernel.org/r/20230729003643.1053367-4-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
tools/testing/selftests/kvm/lib/x86_64/ucall.c