* [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®