On Tue, Dec 30, 2025 at 01:13:40PM -0800, Sean Christopherson wrote:
> Add a helper to detect VMRUN failures so that KVM can guard against its
> own long-standing bug, where KVM neglects to set exitcode[63:32] when
> synthesizing a nested VMFAIL_INVALID VM-Exit.  This will allow fixing
> KVM's mess of treating exitcode as two separate 32-bit values without
> breaking KVM-on-KVM when running on an older, unfixed KVM.
> 
> Cc: Jim Mattson <[email protected]>
> Cc: Yosry Ahmed <[email protected]>
> Signed-off-by: Sean Christopherson <[email protected]>

Reviewed-by: Yosry Ahmed <[email protected]>

> ---
>  arch/x86/kvm/svm/nested.c | 16 +++++++---------
>  arch/x86/kvm/svm/svm.c    |  4 ++--
>  arch/x86/kvm/svm/svm.h    |  5 +++++
>  3 files changed, 14 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> index ba0f11c68372..f5bde972a2b1 100644
> --- a/arch/x86/kvm/svm/nested.c
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -1134,7 +1134,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
>       vmcb12->control.exit_info_1       = vmcb02->control.exit_info_1;
>       vmcb12->control.exit_info_2       = vmcb02->control.exit_info_2;
>  
> -     if (vmcb12->control.exit_code != SVM_EXIT_ERR)
> +     if (!svm_is_vmrun_failure(vmcb12->control.exit_code))
>               nested_save_pending_event_to_vmcb12(svm, vmcb12);
>  
>       if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS))
> @@ -1425,6 +1425,9 @@ static int nested_svm_intercept(struct vcpu_svm *svm)
>       u32 exit_code = svm->vmcb->control.exit_code;
>       int vmexit = NESTED_EXIT_HOST;
>  
> +     if (svm_is_vmrun_failure(exit_code))
> +             return NESTED_EXIT_DONE;
> +
>       switch (exit_code) {
>       case SVM_EXIT_MSR:
>               vmexit = nested_svm_exit_handled_msr(svm);
> @@ -1432,7 +1435,7 @@ static int nested_svm_intercept(struct vcpu_svm *svm)
>       case SVM_EXIT_IOIO:
>               vmexit = nested_svm_intercept_ioio(svm);
>               break;
> -     case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f: {
> +     case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f:
>               /*
>                * Host-intercepted exceptions have been checked already in
>                * nested_svm_exit_special.  There is nothing to do here,
> @@ -1440,15 +1443,10 @@ static int nested_svm_intercept(struct vcpu_svm *svm)
>                */
>               vmexit = NESTED_EXIT_DONE;
>               break;
> -     }
> -     case SVM_EXIT_ERR: {
> -             vmexit = NESTED_EXIT_DONE;
> -             break;
> -     }
> -     default: {
> +     default:
>               if (vmcb12_is_intercept(&svm->nested.ctl, exit_code))
>                       vmexit = NESTED_EXIT_DONE;
> -     }
> +             break;
>       }
>  
>       return vmexit;
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 24d59ccfa40d..c2ddf2e0aa1a 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -3540,7 +3540,7 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, 
> fastpath_t exit_fastpath)
>                       return 1;
>       }
>  
> -     if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
> +     if (svm_is_vmrun_failure(svm->vmcb->control.exit_code)) {
>               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
>               kvm_run->fail_entry.hardware_entry_failure_reason
>                       = svm->vmcb->control.exit_code;
> @@ -4311,7 +4311,7 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct 
> kvm_vcpu *vcpu, u64 run_flags)
>  
>               /* Track VMRUNs that have made past consistency checking */
>               if (svm->nested.nested_run_pending &&
> -                 svm->vmcb->control.exit_code != SVM_EXIT_ERR)
> +                 !svm_is_vmrun_failure(svm->vmcb->control.exit_code))
>                          ++vcpu->stat.nested_run;
>  
>               svm->nested.nested_run_pending = 0;
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index 01be93a53d07..0f006793f973 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -424,6 +424,11 @@ static __always_inline struct vcpu_svm *to_svm(struct 
> kvm_vcpu *vcpu)
>       return container_of(vcpu, struct vcpu_svm, vcpu);
>  }
>  
> +static inline bool svm_is_vmrun_failure(u64 exit_code)
> +{
> +     return (u32)exit_code == (u32)SVM_EXIT_ERR;
> +}
> +
>  /*
>   * Only the PDPTRs are loaded on demand into the shadow MMU.  All other
>   * fields are synchronized on VM-Exit, because accessing the VMCB is cheap.
> -- 
> 2.52.0.351.gbe84eed79e-goog
> 

Reply via email to