From 1a43f741bac797a7312f6c0599fe2425096d5f52 Mon Sep 17 00:00:00 2001 From: Hou Wenlong Date: Mon, 29 Apr 2024 10:48:02 +0800 Subject: [PATCH] KVM: x86/PVM: Explicitly request the GPC refresh if activation fails The commit eb49d06ef264 ("KVM: x86/PVM: Store the valid value for MSR_PVM_VCPU_STRUCT unconditionally") aimed to address the failure to restore a snapshot due to the MSR_PVM_VCPU_STRUCT restoration failure by storing the value before kvm_gpc_activate(). However, this fix worked accidentally as the GPC is refreshed by timer IRQ handling instead of adding memslot. If there is no timer IRQ injecting before the first VM entry, it will cause the host to panic due to the NULL pointer access of 'pvcs_gpc.khva'. Therefore, refer to the PVM specification, a GPC refresh request is made if the GPC fails to activate during the MSR setting by the host. For the guest, setting an invalid MSR value will trigger a triple fault. Additionally, a WARN_ON_ONCE() is added in pvm_vcpu_run() to capture unexpected bugs if 'pvcs_gpc.khva' is NULL and MSR value is not NULL. Fixes: eb49d06ef264 ("KVM: x86/PVM: Store the valid value for MSR_PVM_VCPU_STRUCT unconditionally") Signed-off-by: Hou Wenlong Link: https://github.com/virt-pvm/linux/issues/7 --- arch/x86/kvm/pvm/pvm.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/pvm/pvm.c b/arch/x86/kvm/pvm/pvm.c index 466f989cbcc338..288934c209e3ef 100644 --- a/arch/x86/kvm/pvm/pvm.c +++ b/arch/x86/kvm/pvm/pvm.c @@ -1188,15 +1188,17 @@ static int pvm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) * failure in kvm_gpc_activate() because no memslot has been * added yet. As a consequence, the VM will panic after the VM * restore since the GPC is not active. However, if we store - * the value even if kvm_gpc_activate() fails later when the - * GPC is active, it can be refreshed by the addition of the - * user memory region before the VM entry. + * the value and make a 'KVM_REQ_GPC_REFRESH' request when + * kvm_gpc_activate() fails later, the GPC can be refreshed by + * the request serving before the VM entry. If the guest writes + * an invalid value, the request will trigger a triple fault in + * request serving. */ pvm->msr_vcpu_struct = data; if (!data) kvm_gpc_deactivate(&pvm->pvcs_gpc); else if (kvm_gpc_activate(&pvm->pvcs_gpc, data, PAGE_SIZE)) - return 1; + kvm_make_request(KVM_REQ_GPC_REFRESH, vcpu); break; case MSR_PVM_SUPERVISOR_RSP: pvm->msr_supervisor_rsp = msr_info->data; @@ -2732,6 +2734,16 @@ static fastpath_t pvm_vcpu_run(struct kvm_vcpu *vcpu) if (pvm->non_pvm_mode) return EXIT_FASTPATH_NONE; + /* + * Per to PVM specification, if the GPC of PVCS is invalid, meaning + * 'pvcs_gpc.khva' is NULL, then 'pvm->msr_vcpu_struct' must also be + * NULL. + */ + if (WARN_ON_ONCE(!pvm->pvcs_gpc.khva && pvm->msr_vcpu_struct)) { + kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); + return EXIT_FASTPATH_NONE; + } + trace_kvm_entry(vcpu); pvm_load_guest_xsave_state(vcpu);