* [PATCH] KVM: x86: Don't patch L2's hypercall if L1 intercepts #UD
@ 2026-11-12 13:25 Like Xu
2026-11-12 16:39 ` Sean Christopherson
0 siblings, 1 reply; 2+ messages in thread
From: Like Xu @ 2026-11-12 13:25 UTC (permalink / raw)
To: Sean Christopherson; +Cc: Paolo Bonzini, Oliver Upton, kvm
From: Like Xu <likexu@tencent.com>
The fix_hypercall_test selftest fails when run in an L1 VM on an AMD host:
ret == (u64)-EFAULT
On SVM, L0 always intercepts #UD in vmcb01, so nested_svm_exit_special()
claims every #UD from L2 for L0, before L1's intercepts are consulted.
L0 then emulates L2's VMCALL and, based on the quirk that L0 userspace
configured for L1, patches it to VMMCALL. This ignores L1's decision to
disable KVM_X86_QUIRK_FIX_HYPERCALL_INSN for L2.
Synthesize #UD instead if the vCPU is in L2 and L1 intercepts #UD, so
the nested exception machinery reflects it to L1. Keep patching L2's
instruction when L1 doesn't intercept #UD, as existing userspace relies
on it, e.g. nested SVM selftests execute VMCALL in L2 and expect L1 to
see SVM_EXIT_VMMCALL.
Fixes: f1a9761fbb00 ("KVM: x86: Allow userspace to opt out of hypercall patching")
Signed-off-by: Like Xu <likexu@tencent.com>
---
arch/x86/kvm/x86.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2cd9ee316aada..8c1ae90f1f4b4 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7507,9 +7507,15 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
/*
* If the quirk is disabled, synthesize a #UD and let the guest pick up
- * the pieces.
- */
- if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_FIX_HYPERCALL_INSN)) {
+ * the pieces. Do the same if L1 intercepts #UD from L2, as fixing up
+ * L2's hypercall is then L1's responsibility; the #UD is reflected to
+ * L1. If L1 doesn't intercept #UD, keep patching L2's instruction, as
+ * existing L1 code (e.g. nested SVM selftests executing VMCALL in L2)
+ * relies on it.
+ */
+ if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_FIX_HYPERCALL_INSN) ||
+ (is_guest_mode(vcpu) &&
+ kvm_nested_call(is_exception_vmexit)(vcpu, UD_VECTOR, 0))) {
ctxt->exception.error_code_valid = false;
ctxt->exception.vector = UD_VECTOR;
ctxt->have_exception = true;
--
2.43.7
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH] KVM: x86: Don't patch L2's hypercall if L1 intercepts #UD
2026-11-12 13:25 [PATCH] KVM: x86: Don't patch L2's hypercall if L1 intercepts #UD Like Xu
@ 2026-11-12 16:39 ` Sean Christopherson
0 siblings, 0 replies; 2+ messages in thread
From: Sean Christopherson @ 2026-11-12 16:39 UTC (permalink / raw)
To: Like Xu; +Cc: Paolo Bonzini, Oliver Upton, kvm
On Thu, Nov 12, 2026, Like Xu wrote:
> From: Like Xu <likexu@tencent.com>
>
> The fix_hypercall_test selftest fails when run in an L1 VM on an AMD host:
>
> ret == (u64)-EFAULT
>
> On SVM, L0 always intercepts #UD in vmcb01, so nested_svm_exit_special()
> claims every #UD from L2 for L0, before L1's intercepts are consulted.
> L0 then emulates L2's VMCALL and, based on the quirk that L0 userspace
> configured for L1, patches it to VMMCALL. This ignores L1's decision to
> disable KVM_X86_QUIRK_FIX_HYPERCALL_INSN for L2.
>
> Synthesize #UD instead if the vCPU is in L2 and L1 intercepts #UD, so
> the nested exception machinery reflects it to L1. Keep patching L2's
> instruction when L1 doesn't intercept #UD, as existing userspace relies
> on it, e.g. nested SVM selftests execute VMCALL in L2 and expect L1 to
> see SVM_EXIT_VMMCALL.
>
> Fixes: f1a9761fbb00 ("KVM: x86: Allow userspace to opt out of hypercall patching")
> Signed-off-by: Like Xu <likexu@tencent.com>
I think I'd rather fix this by skipping the selftest, e.g.
diff --git a/tools/testing/selftests/kvm/x86/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86/fix_hypercall_test.c
index f11fcc520f24..bb2fdd622538 100644
--- a/tools/testing/selftests/kvm/x86/fix_hypercall_test.c
+++ b/tools/testing/selftests/kvm/x86/fix_hypercall_test.c
@@ -135,6 +135,7 @@ KVM_ONE_VCPU_TEST(fix_hypercall, disable_quirk, guest_main)
int main(int argc, char *argv[])
{
+ TEST_REQUIRE(!this_cpu_has(X86_FEATURE_HYPERVISOR));
TEST_REQUIRE(kvm_check_cap(KVM_CAP_DISABLE_QUIRKS2) & KVM_X86_QUIRK_FIX_HYPERCALL_INSN);
return test_harness_run(argc, argv);
I doubt there's a deployment that would actually break if L0 stopped patching L2,
but the right solution here really is to disable the quirk in L0. Any risk of
breaking existing setups, however small, just isn't worth it IMO.
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-12 16:39 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-12 13:25 [PATCH] KVM: x86: Don't patch L2's hypercall if L1 intercepts #UD Like Xu
2026-11-12 16:39 ` Sean Christopherson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox