arch/x86/kvm/vmx/tdx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Synthesize a triple fault, i.e. exit to userspace with KVM_EXIT_SHUTDOWN,
instead of returning -EIO from KVM_RUN if KVM encounters an EPT Violation
due to a guest access to a pending page. Returning -EIO implies KVM is
buggy, and most VMMs will respond by completely terminating the VM, versus
rebooting the VM in response to KVM_EXIT_SHUTDOWN. I.e. give the VMM the
option of trying to keep the VM (from the end user's perspective) alive.
Ideally, KVM would probably exit with KVM_EXIT_MEMORY_FAULT, but KVM would
need to extend run->memory_fault so that userspace knows the fault can't be
handled. This scenario specifically occurs when the guest has deliberately
disabled #VEs on unaccepted memory for security purposes, i.e. the guest
literally disabled the mechanism that tells it it screwed up. But, because
this is fatal, and the whole point is to NOT try to fixup the fault,
jumping through hoops to return MEMORY_FAULT instead of SHUTDOWN doesn't
make a whole lot of sense.
Fixes: e6a85781f783 ("KVM: TDX: Detect unexpected SEPT violations due to pending SPTEs")
Cc: stable@vger.kernel.org
Cc: James Houghton <jthoughton@google.com>
Cc: Xiaoyao Li <xiaoyao.li@intel.com>
Cc: Rick Edgecombe <rick.p.edgecombe@intel.com>
Cc: Yan Zhao <yan.y.zhao@intel.com>
Cc: Binbin Wu <binbin.wu@linux.intel.com>
Cc: Ackerley Tng <ackerleytng@google.com>
Cc: Vishal Annapurve <vannapurve@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
Compile tested only.
arch/x86/kvm/vmx/tdx.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 7173ef3fc398..eb82f739a7c0 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -1938,8 +1938,8 @@ static int tdx_handle_ept_violation(struct kvm_vcpu *vcpu)
if (tdx_is_sept_violation_unexpected_pending(vcpu)) {
pr_warn("Guest access before accepting 0x%llx on vCPU %d\n",
gpa, vcpu->vcpu_id);
- kvm_vm_dead(vcpu->kvm);
- return -EIO;
+ kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
+ return 1;
}
/*
* Always treat SEPT violations as write faults. Ignore the
base-commit: 30b5175943e709911702d8a9364145e911f57e3f
--
2.55.0.1082.g2b9226bbc0-goog
On 9/24/2026 12:33 AM, Sean Christopherson wrote:
> Synthesize a triple fault, i.e. exit to userspace with KVM_EXIT_SHUTDOWN,
> instead of returning -EIO from KVM_RUN if KVM encounters an EPT Violation
> due to a guest access to a pending page. Returning -EIO implies KVM is
> buggy, and most VMMs will respond by completely terminating the VM, versus
> rebooting the VM in response to KVM_EXIT_SHUTDOWN. I.e. give the VMM the
> option of trying to keep the VM (from the end user's perspective) alive.
But reboot isn't good, neither.
I still think a new specific exit reason[1] would be better, as I suggested before.
[1] https://lore.kernel.org/kvm/1b0ea352-c645-461b-9e19-5202791f8e2d@intel.com/
> Ideally, KVM would probably exit with KVM_EXIT_MEMORY_FAULT, but KVM would
> need to extend run->memory_fault so that userspace knows the fault can't be
> handled. This scenario specifically occurs when the guest has deliberately
> disabled #VEs on unaccepted memory for security purposes, i.e. the guest
> literally disabled the mechanism that tells it it screwed up. But, because
> this is fatal, and the whole point is to NOT try to fixup the fault,
> jumping through hoops to return MEMORY_FAULT instead of SHUTDOWN doesn't
> make a whole lot of sense.
>
> Fixes: e6a85781f783 ("KVM: TDX: Detect unexpected SEPT violations due to pending SPTEs")
> Cc: stable@vger.kernel.org
> Cc: James Houghton <jthoughton@google.com>
> Cc: Xiaoyao Li <xiaoyao.li@intel.com>
> Cc: Rick Edgecombe <rick.p.edgecombe@intel.com>
> Cc: Yan Zhao <yan.y.zhao@intel.com>
> Cc: Binbin Wu <binbin.wu@linux.intel.com>
> Cc: Ackerley Tng <ackerleytng@google.com>
> Cc: Vishal Annapurve <vannapurve@google.com>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
>
> Compile tested only.
>
> arch/x86/kvm/vmx/tdx.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index 7173ef3fc398..eb82f739a7c0 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -1938,8 +1938,8 @@ static int tdx_handle_ept_violation(struct kvm_vcpu *vcpu)
> if (tdx_is_sept_violation_unexpected_pending(vcpu)) {
> pr_warn("Guest access before accepting 0x%llx on vCPU %d\n",
> gpa, vcpu->vcpu_id);
> - kvm_vm_dead(vcpu->kvm);
> - return -EIO;
> + kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
> + return 1;
> }
> /*
> * Always treat SEPT violations as write faults. Ignore the
>
> base-commit: 30b5175943e709911702d8a9364145e911f57e3f
On Wed, 2026-09-23 at 09:33 -0700, Sean Christopherson wrote:
> Synthesize a triple fault, i.e. exit to userspace with KVM_EXIT_SHUTDOWN,
> instead of returning -EIO from KVM_RUN if KVM encounters an EPT Violation
> due to a guest access to a pending page. Returning -EIO implies KVM is
> buggy, and most VMMs will respond by completely terminating the VM, versus
> rebooting the VM in response to KVM_EXIT_SHUTDOWN. I.e. give the VMM the
> option of trying to keep the VM (from the end user's perspective) alive.
Why not just return KVM_EXIT_SHUTDOWN directly when the pending ept violation is
detected? The synthetic triple fault makes it harder to trace what is happening.
I guess there is some centralization, but harder to trace.
>
> Ideally, KVM would probably exit with KVM_EXIT_MEMORY_FAULT, but KVM would
> need to extend run->memory_fault so that userspace knows the fault can't be
> handled. This scenario specifically occurs when the guest has deliberately
> disabled #VEs on unaccepted memory for security purposes, i.e. the guest
> literally disabled the mechanism that tells it it screwed up. But, because
> this is fatal, and the whole point is to NOT try to fixup the fault,
> jumping through hoops to return MEMORY_FAULT instead of SHUTDOWN doesn't
> make a whole lot of sense.
>
> Fixes: e6a85781f783 ("KVM: TDX: Detect unexpected SEPT violations due to pending SPTEs")
> Cc: stable@vger.kernel.org
> Cc: James Houghton <jthoughton@google.com>
> Cc: Xiaoyao Li <xiaoyao.li@intel.com>
> Cc: Rick Edgecombe <rick.p.edgecombe@intel.com>
> Cc: Yan Zhao <yan.y.zhao@intel.com>
> Cc: Binbin Wu <binbin.wu@linux.intel.com>
> Cc: Ackerley Tng <ackerleytng@google.com>
> Cc: Vishal Annapurve <vannapurve@google.com>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
>
> Compile tested only.
Yan, I vaguely recall you had a test that could trigger this case during the
base enabling?
On Wed, Sep 23, 2026, Rick P Edgecombe wrote:
> On Wed, 2026-09-23 at 09:33 -0700, Sean Christopherson wrote:
> > Synthesize a triple fault, i.e. exit to userspace with KVM_EXIT_SHUTDOWN,
> > instead of returning -EIO from KVM_RUN if KVM encounters an EPT Violation
> > due to a guest access to a pending page. Returning -EIO implies KVM is
> > buggy, and most VMMs will respond by completely terminating the VM, versus
> > rebooting the VM in response to KVM_EXIT_SHUTDOWN. I.e. give the VMM the
> > option of trying to keep the VM (from the end user's perspective) alive.
>
> Why not just return KVM_EXIT_SHUTDOWN directly when the pending ept violation is
> detected? The synthetic triple fault makes it harder to trace what is happening.
> I guess there is some centralization, but harder to trace.
Because it didn't even cross my mind that that's on option. :-) This would be
a great opportunity to do some centralization, e.g. do the below, and then use
kvm_prepare_shutdown_exit() for this case as well.
diff --git arch/x86/kvm/svm/svm.c arch/x86/kvm/svm/svm.c
index f5aa3d7d3a10..34e5bc283479 100644
--- arch/x86/kvm/svm/svm.c
+++ arch/x86/kvm/svm/svm.c
@@ -2164,7 +2164,6 @@ static int mc_interception(struct kvm_vcpu *vcpu)
static int shutdown_interception(struct kvm_vcpu *vcpu)
{
- struct kvm_run *kvm_run = vcpu->run;
struct vcpu_svm *svm = to_svm(vcpu);
@@ -2188,7 +2187,7 @@ static int shutdown_interception(struct kvm_vcpu *vcpu)
kvm_vcpu_reset(vcpu, true);
}
- kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
+ kvm_prepare_shutdown_exit(vcpu);
return 0;
}
diff --git arch/x86/kvm/vmx/tdx.c arch/x86/kvm/vmx/tdx.c
index 7173ef3fc398..0faa7cfd0433 100644
--- arch/x86/kvm/vmx/tdx.c
+++ arch/x86/kvm/vmx/tdx.c
@@ -2091,8 +2091,7 @@ int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
switch (exit_reason.basic) {
case EXIT_REASON_TRIPLE_FAULT:
- vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
- vcpu->mmio_needed = 0;
+ kvm_prepare_shutdown_exit(vcpu);
return 0;
case EXIT_REASON_EXCEPTION_NMI:
return tdx_handle_exception_nmi(vcpu);
diff --git arch/x86/kvm/vmx/vmx.c arch/x86/kvm/vmx/vmx.c
index e8af5e57e1cc..5411eb7f3f26 100644
--- arch/x86/kvm/vmx/vmx.c
+++ arch/x86/kvm/vmx/vmx.c
@@ -5587,8 +5587,7 @@ static __always_inline int handle_external_interrupt(struct kvm_vcpu *vcpu)
static int handle_triple_fault(struct kvm_vcpu *vcpu)
{
- vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
- vcpu->mmio_needed = 0;
+ kvm_prepare_shutdown_exit(vcpu);
return 0;
}
diff --git arch/x86/kvm/x86.c arch/x86/kvm/x86.c
index 1705e7be46ec..e433aa7ee603 100644
--- arch/x86/kvm/x86.c
+++ arch/x86/kvm/x86.c
@@ -8082,8 +8082,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
kvm_nested_call(triple_fault)(vcpu);
if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
- vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
- vcpu->mmio_needed = 0;
+ kvm_prepare_shutdown_exit(vcpu);
r = 0;
goto out;
}
diff --git include/linux/kvm_host.h include/linux/kvm_host.h
index 284fc7d68c60..d133ad33776b 100644
--- include/linux/kvm_host.h
+++ include/linux/kvm_host.h
@@ -2523,6 +2523,12 @@ static inline void kvm_account_pgtable_pages(void *virt, int nr)
/* Max number of entries allowed for each kvm dirty ring */
#define KVM_DIRTY_RING_MAX_ENTRIES 65536
+static inline void kvm_prepare_shutdown_exit(struct kvm_vcpu *vcpu)
+{
+ vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
+ vcpu->mmio_needed = false;
+}
+
static inline void kvm_prepare_memory_fault_exit(struct kvm_vcpu *vcpu,
gpa_t gpa, gpa_t size,
bool is_write, bool is_exec,
On Wed, 2026-09-23 at 16:51 -0700, Sean Christopherson wrote:
> On Wed, Sep 23, 2026, Rick P Edgecombe wrote:
> > On Wed, 2026-09-23 at 09:33 -0700, Sean Christopherson wrote:
> > > Synthesize a triple fault, i.e. exit to userspace with KVM_EXIT_SHUTDOWN,
> > > instead of returning -EIO from KVM_RUN if KVM encounters an EPT Violation
> > > due to a guest access to a pending page. Returning -EIO implies KVM is
> > > buggy, and most VMMs will respond by completely terminating the VM, versus
> > > rebooting the VM in response to KVM_EXIT_SHUTDOWN. I.e. give the VMM the
> > > option of trying to keep the VM (from the end user's perspective) alive.
> >
> > Why not just return KVM_EXIT_SHUTDOWN directly when the pending ept violation is
> > detected? The synthetic triple fault makes it harder to trace what is happening.
> > I guess there is some centralization, but harder to trace.
>
> Because it didn't even cross my mind that that's on option. :-) This would be
> a great opportunity to do some centralization, e.g. do the below, and then use
> kvm_prepare_shutdown_exit() for this case as well.
Ah! Ok. Well, yea then. I'd think it would be better to do it that way. Clean up
seems reasonable to me except...
>
> diff --git arch/x86/kvm/svm/svm.c arch/x86/kvm/svm/svm.c
> index f5aa3d7d3a10..34e5bc283479 100644
> --- arch/x86/kvm/svm/svm.c
> +++ arch/x86/kvm/svm/svm.c
> @@ -2164,7 +2164,6 @@ static int mc_interception(struct kvm_vcpu *vcpu)
>
> static int shutdown_interception(struct kvm_vcpu *vcpu)
> {
> - struct kvm_run *kvm_run = vcpu->run;
> struct vcpu_svm *svm = to_svm(vcpu);
>
>
> @@ -2188,7 +2187,7 @@ static int shutdown_interception(struct kvm_vcpu *vcpu)
> kvm_vcpu_reset(vcpu, true);
> }
>
> - kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
> + kvm_prepare_shutdown_exit(vcpu);
This path grows a vcpu->mmio_needed = false. It probably is ok, but a functional
change.
> return 0;
> }
>
> diff --git arch/x86/kvm/vmx/tdx.c arch/x86/kvm/vmx/tdx.c
> index 7173ef3fc398..0faa7cfd0433 100644
> --- arch/x86/kvm/vmx/tdx.c
> +++ arch/x86/kvm/vmx/tdx.c
> @@ -2091,8 +2091,7 @@ int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
>
> switch (exit_reason.basic) {
> case EXIT_REASON_TRIPLE_FAULT:
> - vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
> - vcpu->mmio_needed = 0;
> + kvm_prepare_shutdown_exit(vcpu);
> return 0;
> case EXIT_REASON_EXCEPTION_NMI:
> return tdx_handle_exception_nmi(vcpu);
> diff --git arch/x86/kvm/vmx/vmx.c arch/x86/kvm/vmx/vmx.c
> index e8af5e57e1cc..5411eb7f3f26 100644
> --- arch/x86/kvm/vmx/vmx.c
> +++ arch/x86/kvm/vmx/vmx.c
> @@ -5587,8 +5587,7 @@ static __always_inline int handle_external_interrupt(struct kvm_vcpu *vcpu)
>
> static int handle_triple_fault(struct kvm_vcpu *vcpu)
> {
> - vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
> - vcpu->mmio_needed = 0;
> + kvm_prepare_shutdown_exit(vcpu);
> return 0;
> }
>
> diff --git arch/x86/kvm/x86.c arch/x86/kvm/x86.c
> index 1705e7be46ec..e433aa7ee603 100644
> --- arch/x86/kvm/x86.c
> +++ arch/x86/kvm/x86.c
> @@ -8082,8 +8082,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
> kvm_nested_call(triple_fault)(vcpu);
>
> if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
> - vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
> - vcpu->mmio_needed = 0;
> + kvm_prepare_shutdown_exit(vcpu);
> r = 0;
> goto out;
> }
> diff --git include/linux/kvm_host.h include/linux/kvm_host.h
> index 284fc7d68c60..d133ad33776b 100644
> --- include/linux/kvm_host.h
> +++ include/linux/kvm_host.h
> @@ -2523,6 +2523,12 @@ static inline void kvm_account_pgtable_pages(void *virt, int nr)
> /* Max number of entries allowed for each kvm dirty ring */
> #define KVM_DIRTY_RING_MAX_ENTRIES 65536
>
> +static inline void kvm_prepare_shutdown_exit(struct kvm_vcpu *vcpu)
> +{
> + vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
> + vcpu->mmio_needed = false;
> +}
> +
> static inline void kvm_prepare_memory_fault_exit(struct kvm_vcpu *vcpu,
> gpa_t gpa, gpa_t size,
> bool is_write, bool is_exec,
>
© 2016 - 2026 Red Hat, Inc.