[PATCH 31/45] KVM: x86: "Handle" failed decode when skipping instructions

From: Paolo Bonzini

Date: Mon Nov 02 2026 - 13:02:51 EST


When calling into the emulator to skip an instruction, the caller has
already performed the side effects of the instruction and cannot
propagate -EFAULT. Mark the VM dead.

Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
---
arch/x86/kvm/svm/svm.c | 9 +++++++--
arch/x86/kvm/vmx/vmx.c | 10 +++++++---
arch/x86/kvm/x86.c | 4 ++--
3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 205d8783aa13..2601f8359137 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -304,6 +304,7 @@ static int __svm_skip_emulated_instruction(struct kvm_vcpu *vcpu,
{
struct vcpu_svm *svm = to_svm(vcpu);
unsigned long old_rflags;
+ int r;

/*
* SEV-ES does not expose the next RIP. The RIP update is controlled by
@@ -321,7 +322,10 @@ static int __svm_skip_emulated_instruction(struct kvm_vcpu *vcpu,
if (unlikely(!commit_side_effects))
old_rflags = svm->vmcb->save.rflags;

- if (!kvm_emulate_instruction(vcpu, emul_type))
+ r = kvm_emulate_instruction(vcpu, emul_type);
+ if (r < 0)
+ kvm_vm_dead(vcpu->kvm);
+ if (r <= 0)
return 0;

if (unlikely(!commit_side_effects))
@@ -2128,7 +2132,8 @@ static int icebp_interception(struct kvm_vcpu *vcpu)
* instead of after it (and SVM doesn't provide enough information for
* KVM to detect and manually advance the pre-#DB RIP).
*/
- svm_skip_emulated_instruction(vcpu);
+ if (!svm_skip_emulated_instruction(vcpu))
+ return 0;
kvm_queue_exception(vcpu, DB_VECTOR);
return 1;
}
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 80dfb3c6268b..27cb0d64fb5c 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1809,6 +1809,7 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
union vmx_exit_reason exit_reason = vt_get_exit_reason(vcpu);
unsigned long rip, orig_rip;
u32 instr_len;
+ int r;

/*
* Using VMCS.VM_EXIT_INSTRUCTION_LEN on EPT misconfig depends on
@@ -1857,7 +1858,10 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
#endif
kvm_rip_write(vcpu, rip);
} else {
- if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP))
+ r = kvm_emulate_instruction(vcpu, EMULTYPE_SKIP);
+ if (r < 0)
+ kvm_vm_dead(vcpu->kvm);
+ if (r <= 0)
return 0;
}

@@ -5538,8 +5542,8 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
* higher priority. Note, skipping ICEBP still clears
* STI and MOVSS blocking.
*/
- if (is_icebp(intr_info))
- WARN_ON(!skip_emulated_instruction(vcpu));
+ if (is_icebp(intr_info) && !skip_emulated_instruction(vcpu))
+ return 0;

kvm_queue_exception_p(vcpu, DB_VECTOR, dr6);
return 1;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 5f7f87ff4d17..5818101d1d8a 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6235,8 +6235,8 @@ int kvm_skip_emulated_instruction(struct kvm_vcpu *vcpu)
int r;

r = kvm_x86_call(skip_emulated_instruction)(vcpu);
- if (unlikely(!r))
- return 0;
+ if (unlikely(r <= 0))
+ return r;

kvm_pmu_instruction_retired(vcpu);

--
2.52.0