After VMRUN in guest mode, nested_sync_control_from_vmcb02() syncs fields written by the CPU from vmcb02 to the cached vmcb12. This is because the cached vmcb12 is used as the authoritative copy of some of the controls, and is the payload when saving/restoring nested state. next_rip is also written by the CPU (in some cases) after VMRUN, but is not sync'd to cached vmcb12. As a result, it is corrupted after save/restore (replaced by the original value written by L1 on nested VMRUN). This could cause problems for both KVM (e.g. when injecting a soft IRQ) or L1 (e.g. when using next_rip to advance RIP after emulating an instruction). Fix this by sync'ing next_rip in nested_sync_control_from_vmcb02(). Move the call to nested_sync_control_from_vmcb02() (and the entire is_guest_mode() block) after svm_complete_interrupts(), as it may update next_rip in vmcb02. Fixes: cc440cdad5b7 ("KVM: nSVM: implement KVM_GET_NESTED_STATE and KVM_SET_NESTED_STATE") CC: stable@vger.kernel.org Signed-off-by: Yosry Ahmed --- arch/x86/kvm/svm/nested.c | 6 ++++-- arch/x86/kvm/svm/svm.c | 26 +++++++++++++++----------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index de90b104a0dd..70086ba6497f 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -519,8 +519,10 @@ void nested_copy_vmcb_save_to_cache(struct vcpu_svm *svm, void nested_sync_control_from_vmcb02(struct vcpu_svm *svm) { u32 mask; - svm->nested.ctl.event_inj = svm->vmcb->control.event_inj; - svm->nested.ctl.event_inj_err = svm->vmcb->control.event_inj_err; + + svm->nested.ctl.event_inj = svm->vmcb->control.event_inj; + svm->nested.ctl.event_inj_err = svm->vmcb->control.event_inj_err; + svm->nested.ctl.next_rip = svm->vmcb->control.next_rip; /* Only a few fields of int_ctl are written by the processor. */ mask = V_IRQ_MASK | V_TPR_MASK; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 5f0136dbdde6..6d8d4d19455e 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4399,17 +4399,6 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags) sync_cr8_to_lapic(vcpu); svm->next_rip = 0; - if (is_guest_mode(vcpu)) { - nested_sync_control_from_vmcb02(svm); - - /* Track VMRUNs that have made past consistency checking */ - if (svm->nested.nested_run_pending && - !svm_is_vmrun_failure(svm->vmcb->control.exit_code)) - ++vcpu->stat.nested_run; - - svm->nested.nested_run_pending = 0; - } - svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; /* @@ -4435,6 +4424,21 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags) svm_complete_interrupts(vcpu); + /* + * svm_complete_interrupts() may update svm->vmcb->control.next_rip, + * which is sync'd by nested_sync_control_from_vmcb02() below. + */ + if (is_guest_mode(vcpu)) { + nested_sync_control_from_vmcb02(svm); + + /* Track VMRUNs that have made past consistency checking */ + if (svm->nested.nested_run_pending && + !svm_is_vmrun_failure(svm->vmcb->control.exit_code)) + ++vcpu->stat.nested_run; + + svm->nested.nested_run_pending = 0; + } + return svm_exit_handlers_fastpath(vcpu); } base-commit: e944fe2c09f405a2e2d147145c9b470084bc4c9a -- 2.53.0.rc2.204.g2597b5adb4-goog