]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: SVM: check validity of VMCB controls when returning from SMM
authorPaolo Bonzini <pbonzini@redhat.com>
Mon, 9 Mar 2026 11:40:52 +0000 (12:40 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 11 Mar 2026 17:41:11 +0000 (18:41 +0100)
The VMCB12 is stored in guest memory and can be mangled while in SMM; it
is then reloaded by svm_leave_smm(), but it is not checked again for
validity.

Move the cached vmcb12 control and save consistency checks out of
svm_set_nested_state() and into a helper, and reuse it in
svm_leave_smm().

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/svm/nested.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/svm/svm.h

index 53ab6ce3cc26dc5944cf68ee0d65c97d07305158..b36c33255bed66f1a61a787a78402bb9d1be5e26 100644 (file)
@@ -418,6 +418,15 @@ static bool nested_vmcb_check_controls(struct kvm_vcpu *vcpu)
        return __nested_vmcb_check_controls(vcpu, ctl);
 }
 
+int nested_svm_check_cached_vmcb12(struct kvm_vcpu *vcpu)
+{
+       if (!nested_vmcb_check_save(vcpu) ||
+           !nested_vmcb_check_controls(vcpu))
+               return -EINVAL;
+
+       return 0;
+}
+
 /*
  * If a feature is not advertised to L1, clear the corresponding vmcb12
  * intercept.
@@ -1028,8 +1037,7 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
        nested_copy_vmcb_control_to_cache(svm, &vmcb12->control);
        nested_copy_vmcb_save_to_cache(svm, &vmcb12->save);
 
-       if (!nested_vmcb_check_save(vcpu) ||
-           !nested_vmcb_check_controls(vcpu)) {
+       if (nested_svm_check_cached_vmcb12(vcpu) < 0) {
                vmcb12->control.exit_code    = SVM_EXIT_ERR;
                vmcb12->control.exit_info_1  = 0;
                vmcb12->control.exit_info_2  = 0;
index 2772f22df7edf607f20f78bcd09bf6ba740a6462..4eb2c36b8ff21783f935f85edf093a473428921a 100644 (file)
@@ -4880,6 +4880,10 @@ static int svm_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
        vmcb12 = map.hva;
        nested_copy_vmcb_control_to_cache(svm, &vmcb12->control);
        nested_copy_vmcb_save_to_cache(svm, &vmcb12->save);
+
+       if (nested_svm_check_cached_vmcb12(vcpu) < 0)
+               goto unmap_save;
+
        ret = enter_svm_guest_mode(vcpu, smram64->svm_guest_vmcb_gpa, vmcb12, false);
 
        if (ret)
index ebd7b36b1ceb9b1ba1c6f7ef5622f6fc1ff8a232..6942e6b0eda67e36bdfae8e891b4eeb27a88291e 100644 (file)
@@ -797,6 +797,7 @@ static inline int nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code)
 
 int nested_svm_exit_handled(struct vcpu_svm *svm);
 int nested_svm_check_permissions(struct kvm_vcpu *vcpu);
+int nested_svm_check_cached_vmcb12(struct kvm_vcpu *vcpu);
 int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
                               bool has_error_code, u32 error_code);
 int nested_svm_exit_special(struct vcpu_svm *svm);