mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/4] KVM: nVMX: Adjust VMPTRLD/VMPTRST behavior with active eVMCS
@ 2026-08-14 16:22 Vitaly Kuznetsov
  2026-08-14 16:22 ` [PATCH 1/4] KVM: nVMX: Make VMPTRLD result in #UD when eVMCS is used Vitaly Kuznetsov
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Vitaly Kuznetsov @ 2026-08-14 16:22 UTC (permalink / raw)
  To: kvm, Sean Christopherson, Paolo Bonzini; +Cc: f734222792, linux-kernel

It was reported (https://bugzilla.kernel.org/show_bug.cgi?id=221841) that
KVM's emulation of VMPTRLD/VMPTRST instructions when Enlightened VMCS is
active is sub-optimal: returning '1' does not make the L1 guest skip the
instruction so a hang is likely to happen. While TLFS does not really
specify the expected behavior, genuine Hyper-V seems to return #UD for
VMPTRLD and eVMCS pointer for VMPTRST. Alter the behavior in KVM and check
it in selftests.

Note: this is not a security issue. Misbehaving L1 can only do self-harm
by doing VMPTRLD/VMPTRST when it also uses eVMCS.

Vitaly Kuznetsov (4):
  KVM: nVMX: Make VMPTRLD result in #UD when eVMCS is used
  KVM: nVMX: Make VMPTRST return eVMCS GPA when it is used
  KVM: selftests: Adapt to the updated VMPTRST behavior when eVMCS is
    used
  KVM: selftests: Check VMPTRLD with active eVMCS

 arch/x86/kvm/vmx/nested.c                     | 22 +++++++++++++------
 tools/testing/selftests/kvm/include/x86/vmx.h |  6 -----
 .../testing/selftests/kvm/x86/hyperv_evmcs.c  | 18 ++++++++++-----
 3 files changed, 28 insertions(+), 18 deletions(-)

-- 
2.55.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/4] KVM: nVMX: Make VMPTRLD result in #UD when eVMCS is used
  2026-08-14 16:22 [PATCH 0/4] KVM: nVMX: Adjust VMPTRLD/VMPTRST behavior with active eVMCS Vitaly Kuznetsov
@ 2026-08-14 16:22 ` Vitaly Kuznetsov
  2026-08-14 16:22 ` [PATCH 2/4] KVM: nVMX: Make VMPTRST return eVMCS GPA when it " Vitaly Kuznetsov
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Vitaly Kuznetsov @ 2026-08-14 16:22 UTC (permalink / raw)
  To: kvm, Sean Christopherson, Paolo Bonzini; +Cc: f734222792, linux-kernel

VMPTRLD with active eVMCS is already forbidden, however, returning 1
without skipping the instruction or queuing an exception will likely
result in L1 getting stuck. Genuine Hyper-V seems to inject #UD under
similar circumstances, mimic the behavior in KVM.

Reported-by: f734222792@gmail.com
Link: https://bugzilla.kernel.org/show_bug.cgi?id=221841
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
 arch/x86/kvm/vmx/nested.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index ddf6df7bee93..216f54a0b8ae 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -5879,6 +5879,12 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
 	if (!nested_vmx_check_permission(vcpu))
 		return 1;
 
+	/* Forbid normal VMPTRLD if Enlightened version was used */
+	if (nested_vmx_is_evmptr12_valid(vmx)) {
+		kvm_queue_exception(vcpu, UD_VECTOR);
+		return 1;
+	}
+
 	if (nested_vmx_get_vmptr(vcpu, &vmptr, &r))
 		return r;
 
@@ -5888,10 +5894,6 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
 	if (vmptr == vmx->nested.vmxon_ptr)
 		return nested_vmx_fail(vcpu, VMXERR_VMPTRLD_VMXON_POINTER);
 
-	/* Forbid normal VMPTRLD if Enlightened version was used */
-	if (nested_vmx_is_evmptr12_valid(vmx))
-		return 1;
-
 	if (vmx->nested.current_vmptr != vmptr) {
 		struct gfn_to_hva_cache *ghc = &vmx->nested.vmcs12_cache;
 		struct vmcs_hdr hdr;
-- 
2.55.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/4] KVM: nVMX: Make VMPTRST return eVMCS GPA when it is used
  2026-08-14 16:22 [PATCH 0/4] KVM: nVMX: Adjust VMPTRLD/VMPTRST behavior with active eVMCS Vitaly Kuznetsov
  2026-08-14 16:22 ` [PATCH 1/4] KVM: nVMX: Make VMPTRLD result in #UD when eVMCS is used Vitaly Kuznetsov
@ 2026-08-14 16:22 ` Vitaly Kuznetsov
  2026-08-14 16:22 ` [PATCH 3/4] KVM: selftests: Adapt to the updated VMPTRST behavior when eVMCS " Vitaly Kuznetsov
  2026-08-14 16:22 ` [PATCH 4/4] KVM: selftests: Check VMPTRLD with active eVMCS Vitaly Kuznetsov
  3 siblings, 0 replies; 5+ messages in thread
From: Vitaly Kuznetsov @ 2026-08-14 16:22 UTC (permalink / raw)
  To: kvm, Sean Christopherson, Paolo Bonzini; +Cc: f734222792, linux-kernel

VMPTRST with active eVMCS is currently forbidden, however, returning 1
without skipping the instruction will likely result in L1 getting
stuck. While TLFS does not specify the expected behavior, genuine Hyper-V
seems to be returning eVMCS GPA. Implement the same behavior in KVM.

Reported-by: f734222792@gmail.com
Link: https://bugzilla.kernel.org/show_bug.cgi?id=221841
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
 arch/x86/kvm/vmx/nested.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 216f54a0b8ae..0f5e4b47ecb1 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -5946,7 +5946,7 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu)
 {
 	unsigned long exit_qual = vmx_get_exit_qual(vcpu);
 	u32 instr_info = vmcs_read32(VMX_INSTRUCTION_INFO);
-	gpa_t current_vmptr = to_vmx(vcpu)->nested.current_vmptr;
+	gpa_t current_vmptr;
 	struct x86_exception e;
 	gva_t gva;
 	int r;
@@ -5954,8 +5954,14 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu)
 	if (!nested_vmx_check_permission(vcpu))
 		return 1;
 
-	if (unlikely(nested_vmx_is_evmptr12_valid(to_vmx(vcpu))))
-		return 1;
+	/*
+	 * Hyper-V TLFS does not specify the behavior of VMPTRST when eVMCS is used
+	 * but genuine Hyper-V seems to be returning eVMCS GPA.
+	 */
+	if (nested_vmx_is_evmptr12_valid(to_vmx(vcpu)))
+		current_vmptr = to_vmx(vcpu)->nested.hv_evmcs_vmptr;
+	else
+		current_vmptr = to_vmx(vcpu)->nested.current_vmptr;
 
 	if (get_vmx_mem_address(vcpu, exit_qual, instr_info,
 				true, sizeof(gpa_t), &gva))
-- 
2.55.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 3/4] KVM: selftests: Adapt to the updated VMPTRST behavior when eVMCS is used
  2026-08-14 16:22 [PATCH 0/4] KVM: nVMX: Adjust VMPTRLD/VMPTRST behavior with active eVMCS Vitaly Kuznetsov
  2026-08-14 16:22 ` [PATCH 1/4] KVM: nVMX: Make VMPTRLD result in #UD when eVMCS is used Vitaly Kuznetsov
  2026-08-14 16:22 ` [PATCH 2/4] KVM: nVMX: Make VMPTRST return eVMCS GPA when it " Vitaly Kuznetsov
@ 2026-08-14 16:22 ` Vitaly Kuznetsov
  2026-08-14 16:22 ` [PATCH 4/4] KVM: selftests: Check VMPTRLD with active eVMCS Vitaly Kuznetsov
  3 siblings, 0 replies; 5+ messages in thread
From: Vitaly Kuznetsov @ 2026-08-14 16:22 UTC (permalink / raw)
  To: kvm, Sean Christopherson, Paolo Bonzini; +Cc: f734222792, linux-kernel

Previously, VMPTRST was forbidden with eVMCS and selftests were mocking the
correct behavior in vmptrst() by returning enlightened vmptr directly.
Since KVM's behavior has changed to match genuine Hyper-V, adjust evmcs
test accordingly.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
 tools/testing/selftests/kvm/include/x86/vmx.h  | 3 ---
 tools/testing/selftests/kvm/x86/hyperv_evmcs.c | 5 ++---
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/selftests/kvm/include/x86/vmx.h
index 90fffaf91595..047d02aa9688 100644
--- a/tools/testing/selftests/kvm/include/x86/vmx.h
+++ b/tools/testing/selftests/kvm/include/x86/vmx.h
@@ -341,9 +341,6 @@ static inline int vmptrst(u64 *value)
 	u64 tmp;
 	u8 ret;
 
-	if (enable_evmcs)
-		return evmcs_vmptrst(value);
-
 	__asm__ __volatile__("vmptrst %[value]; setna %[ret]"
 		: [value]"=m"(tmp), [ret]"=rm"(ret)
 		: : "cc", "memory");
diff --git a/tools/testing/selftests/kvm/x86/hyperv_evmcs.c b/tools/testing/selftests/kvm/x86/hyperv_evmcs.c
index c7fa114aee20..88262ddf7fcb 100644
--- a/tools/testing/selftests/kvm/x86/hyperv_evmcs.c
+++ b/tools/testing/selftests/kvm/x86/hyperv_evmcs.c
@@ -95,16 +95,15 @@ void guest_code(struct vmx_pages *vmx_pages, struct hyperv_test_pages *hv_pages,
 	GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages));
 	GUEST_SYNC(3);
 	GUEST_ASSERT(load_evmcs(hv_pages));
-	GUEST_ASSERT(vmptrstz() == hv_pages->enlightened_vmcs_gpa);
+	/* VMPTRST returns -1 until VMLAUNCH with eVMCS ptr set */
+	GUEST_ASSERT(vmptrstz() == -1);
 
 	GUEST_SYNC(4);
-	GUEST_ASSERT(vmptrstz() == hv_pages->enlightened_vmcs_gpa);
 
 	prepare_vmcs(vmx_pages, l2_guest_code,
 		     &l2_guest_stack[L2_GUEST_STACK_SIZE]);
 
 	GUEST_SYNC(5);
-	GUEST_ASSERT(vmptrstz() == hv_pages->enlightened_vmcs_gpa);
 	current_evmcs->revision_id = -1u;
 	GUEST_ASSERT(vmlaunch());
 	current_evmcs->revision_id = EVMCS_VERSION;
-- 
2.55.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 4/4] KVM: selftests: Check VMPTRLD with active eVMCS
  2026-08-14 16:22 [PATCH 0/4] KVM: nVMX: Adjust VMPTRLD/VMPTRST behavior with active eVMCS Vitaly Kuznetsov
                   ` (2 preceding siblings ...)
  2026-08-14 16:22 ` [PATCH 3/4] KVM: selftests: Adapt to the updated VMPTRST behavior when eVMCS " Vitaly Kuznetsov
@ 2026-08-14 16:22 ` Vitaly Kuznetsov
  3 siblings, 0 replies; 5+ messages in thread
From: Vitaly Kuznetsov @ 2026-08-14 16:22 UTC (permalink / raw)
  To: kvm, Sean Christopherson, Paolo Bonzini; +Cc: f734222792, linux-kernel

Check that VMPTRLD when eVMCS is active results in #UD. This matches
genuine Hyper-V's behavior.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
 tools/testing/selftests/kvm/include/x86/vmx.h  |  3 ---
 tools/testing/selftests/kvm/x86/hyperv_evmcs.c | 13 +++++++++++--
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/selftests/kvm/include/x86/vmx.h
index 047d02aa9688..e2178a6683ca 100644
--- a/tools/testing/selftests/kvm/include/x86/vmx.h
+++ b/tools/testing/selftests/kvm/include/x86/vmx.h
@@ -325,9 +325,6 @@ static inline int vmptrld(u64 vmcs_pa)
 {
 	u8 ret;
 
-	if (enable_evmcs)
-		return -1;
-
 	__asm__ __volatile__ ("vmptrld %[pa]; setna %[ret]"
 		: [ret]"=rm"(ret)
 		: [pa]"m"(vmcs_pa)
diff --git a/tools/testing/selftests/kvm/x86/hyperv_evmcs.c b/tools/testing/selftests/kvm/x86/hyperv_evmcs.c
index 88262ddf7fcb..6a6d940a7891 100644
--- a/tools/testing/selftests/kvm/x86/hyperv_evmcs.c
+++ b/tools/testing/selftests/kvm/x86/hyperv_evmcs.c
@@ -18,12 +18,16 @@
 #include "hyperv.h"
 #include "vmx.h"
 
+#define VMLAUNCH_INSN_SIZE 3
+#define VMPTRLD_INSN_SIZE 5
+
 static int ud_count;
+static int ud_insn_skip_size;
 
 static void guest_ud_handler(struct ex_regs *regs)
 {
 	ud_count++;
-	regs->rip += 3; /* VMLAUNCH */
+	regs->rip += ud_insn_skip_size;
 }
 
 static void guest_nmi_handler(struct ex_regs *regs)
@@ -182,10 +186,15 @@ void guest_code(struct vmx_pages *vmx_pages, struct hyperv_test_pages *hv_pages,
 	GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
 	GUEST_SYNC(11);
 
+	ud_insn_skip_size = VMPTRLD_INSN_SIZE;
+	vmptrld(hv_pages->enlightened_vmcs_gpa);
+	GUEST_ASSERT(ud_count == 1);
+
 	/* Try enlightened vmptrld with an incorrect GPA */
+	ud_insn_skip_size = VMLAUNCH_INSN_SIZE;
 	evmcs_vmptrld(0xdeadbeef, hv_pages->enlightened_vmcs);
 	GUEST_ASSERT(vmlaunch());
-	GUEST_ASSERT(ud_count == 1);
+	GUEST_ASSERT(ud_count == 2);
 	GUEST_DONE();
 }
 
-- 
2.55.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-08-14 16:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-14 16:22 [PATCH 0/4] KVM: nVMX: Adjust VMPTRLD/VMPTRST behavior with active eVMCS Vitaly Kuznetsov
2026-08-14 16:22 ` [PATCH 1/4] KVM: nVMX: Make VMPTRLD result in #UD when eVMCS is used Vitaly Kuznetsov
2026-08-14 16:22 ` [PATCH 2/4] KVM: nVMX: Make VMPTRST return eVMCS GPA when it " Vitaly Kuznetsov
2026-08-14 16:22 ` [PATCH 3/4] KVM: selftests: Adapt to the updated VMPTRST behavior when eVMCS " Vitaly Kuznetsov
2026-08-14 16:22 ` [PATCH 4/4] KVM: selftests: Check VMPTRLD with active eVMCS Vitaly Kuznetsov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®