public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Michael Roth <michael.roth@amd.com>
To: <pbonzini@redhat.com>
Cc: <kvm@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<ashish.kalra@amd.com>, <thomas.lendacky@amd.com>,
	<seanjc@google.com>, <rick.p.edgecombe@intel.com>
Subject: [PATCH v2] KVM: SEV: Fix guest memory leak when handling guest requests
Date: Mon, 20 May 2024 18:02:00 -0500	[thread overview]
Message-ID: <20240520230200.1161826-1-michael.roth@amd.com> (raw)
In-Reply-To: <20240518150457.1033295-1-michael.roth@amd.com>

Before forwarding guest requests to firmware, KVM takes a reference on
the 2 pages the guest uses for its request/response buffers. Make sure
to release these when cleaning up after the request is completed.

Also modify the logic to fail immediately (rather than report failure to
the guest) if there is an error returning the guest pages to their
expected state after the firmware command completes. Continue to
propagate firmware errors to the guest as per the GHCB spec, however.

Suggested-by: Sean Christopherson <seanjc@google.com> #for error-handling
Signed-off-by: Michael Roth <michael.roth@amd.com>
---
v2:
 - Fail to userspace if reclaim fails rather than trying to inform the
   guest of the error (Sean)
 - Remove the setup/cleanup helpers so that the cleanup logic is easier
   to follow (Sean)
 - Full original patch with this and other pending fix squashed in:
   https://github.com/mdroth/linux/commit/b4f51e38da22a2b163c546cb2a3aefd04446b3c7

 arch/x86/kvm/svm/sev.c | 105 ++++++++++++++++++-----------------------
 1 file changed, 47 insertions(+), 58 deletions(-)

diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 252bf7564f4b..446f9811cdaf 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -3919,11 +3919,16 @@ static int sev_snp_ap_creation(struct vcpu_svm *svm)
 	return ret;
 }
 
-static int snp_setup_guest_buf(struct kvm *kvm, struct sev_data_snp_guest_request *data,
-			       gpa_t req_gpa, gpa_t resp_gpa)
+static int snp_handle_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t resp_gpa)
 {
-	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+	struct sev_data_snp_guest_request data = {0};
+	struct kvm *kvm = svm->vcpu.kvm;
 	kvm_pfn_t req_pfn, resp_pfn;
+	sev_ret_code fw_err = 0;
+	int ret;
+
+	if (!sev_snp_guest(kvm))
+		return -EINVAL;
 
 	if (!PAGE_ALIGNED(req_gpa) || !PAGE_ALIGNED(resp_gpa))
 		return -EINVAL;
@@ -3933,64 +3938,49 @@ static int snp_setup_guest_buf(struct kvm *kvm, struct sev_data_snp_guest_reques
 		return -EINVAL;
 
 	resp_pfn = gfn_to_pfn(kvm, gpa_to_gfn(resp_gpa));
-	if (is_error_noslot_pfn(resp_pfn))
-		return -EINVAL;
-
-	if (rmp_make_private(resp_pfn, 0, PG_LEVEL_4K, 0, true))
-		return -EINVAL;
-
-	data->gctx_paddr = __psp_pa(sev->snp_context);
-	data->req_paddr = __sme_set(req_pfn << PAGE_SHIFT);
-	data->res_paddr = __sme_set(resp_pfn << PAGE_SHIFT);
-
-	return 0;
-}
-
-static int snp_cleanup_guest_buf(struct sev_data_snp_guest_request *data)
-{
-	u64 pfn = __sme_clr(data->res_paddr) >> PAGE_SHIFT;
-
-	if (snp_page_reclaim(pfn) || rmp_make_shared(pfn, PG_LEVEL_4K))
-		return -EINVAL;
-
-	return 0;
-}
-
-static int __snp_handle_guest_req(struct kvm *kvm, gpa_t req_gpa, gpa_t resp_gpa,
-				  sev_ret_code *fw_err)
-{
-	struct sev_data_snp_guest_request data = {0};
-	int ret;
-
-	if (!sev_snp_guest(kvm))
-		return -EINVAL;
-
-	ret = snp_setup_guest_buf(kvm, &data, req_gpa, resp_gpa);
-	if (ret)
-		return ret;
+	if (is_error_noslot_pfn(resp_pfn)) {
+		ret = -EINVAL;
+		goto release_req;
+	}
 
-	ret = sev_issue_cmd(kvm, SEV_CMD_SNP_GUEST_REQUEST, &data, fw_err);
-	if (ret)
-		return ret;
+	if (rmp_make_private(resp_pfn, 0, PG_LEVEL_4K, 0, true)) {
+		ret = -EINVAL;
+		kvm_release_pfn_clean(resp_pfn);
+		goto release_req;
+	}
 
-	ret = snp_cleanup_guest_buf(&data);
-	if (ret)
-		return ret;
+	data.gctx_paddr = __psp_pa(to_kvm_sev_info(kvm)->snp_context);
+	data.req_paddr = __sme_set(req_pfn << PAGE_SHIFT);
+	data.res_paddr = __sme_set(resp_pfn << PAGE_SHIFT);
 
-	return 0;
-}
+	ret = sev_issue_cmd(kvm, SEV_CMD_SNP_GUEST_REQUEST, &data, &fw_err);
 
-static void snp_handle_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t resp_gpa)
-{
-	struct kvm_vcpu *vcpu = &svm->vcpu;
-	struct kvm *kvm = vcpu->kvm;
-	sev_ret_code fw_err = 0;
-	int vmm_ret = 0;
-
-	if (__snp_handle_guest_req(kvm, req_gpa, resp_gpa, &fw_err))
-		vmm_ret = SNP_GUEST_VMM_ERR_GENERIC;
+	/*
+	 * If the pages can't be placed back in the expected state then it is
+	 * more reliable to always report the error to userspace than to try to
+	 * let the guest deal with it somehow. Either way, the guest would
+	 * likely terminate itself soon after a guest request failure anyway.
+	 */
+	if (snp_page_reclaim(resp_pfn) ||
+	    host_rmp_make_shared(resp_pfn, PG_LEVEL_4K)) {
+		ret = -EIO;
+		goto release_req;
+	}
 
-	ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, SNP_GUEST_ERR(vmm_ret, fw_err));
+	/*
+	 * Unlike with reclaim failures, firmware failures should be
+	 * communicated back to the guest via SW_EXITINFO2 rather than be
+	 * treated as immediately fatal.
+	 */
+	ghcb_set_sw_exit_info_2(svm->sev_es.ghcb,
+				SNP_GUEST_ERR(ret ? SNP_GUEST_VMM_ERR_GENERIC : 0,
+					      fw_err));
+	ret = 1; /* resume guest */
+	kvm_release_pfn_dirty(resp_pfn);
+
+release_req:
+	kvm_release_pfn_clean(req_pfn);
+	return ret;
 }
 
 static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
@@ -4268,8 +4258,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
 		ret = 1;
 		break;
 	case SVM_VMGEXIT_GUEST_REQUEST:
-		snp_handle_guest_req(svm, control->exit_info_1, control->exit_info_2);
-		ret = 1;
+		ret = snp_handle_guest_req(svm, control->exit_info_1, control->exit_info_2);
 		break;
 	case SVM_VMGEXIT_UNSUPPORTED_EVENT:
 		vcpu_unimpl(vcpu,
-- 
2.25.1


  parent reply	other threads:[~2024-05-20 23:02 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-10 21:10 [PULL 00/19] KVM: Add AMD Secure Nested Paging (SEV-SNP) Hypervisor Support Michael Roth
2024-05-10 21:10 ` [PULL 01/19] KVM: MMU: Disable fast path if KVM_EXIT_MEMORY_FAULT is needed Michael Roth
2024-05-10 21:10 ` [PULL 02/19] KVM: SEV: Select KVM_GENERIC_PRIVATE_MEM when CONFIG_KVM_AMD_SEV=y Michael Roth
2024-05-10 21:10 ` [PULL 03/19] KVM: SEV: Add initial SEV-SNP support Michael Roth
2024-05-10 21:10 ` [PULL 04/19] KVM: SEV: Add KVM_SEV_SNP_LAUNCH_START command Michael Roth
2024-05-10 21:10 ` [PULL 05/19] KVM: SEV: Add KVM_SEV_SNP_LAUNCH_UPDATE command Michael Roth
2024-05-10 21:10 ` [PULL 06/19] KVM: SEV: Add KVM_SEV_SNP_LAUNCH_FINISH command Michael Roth
2024-05-10 21:10 ` [PULL 07/19] KVM: SEV: Add support to handle GHCB GPA register VMGEXIT Michael Roth
2024-05-10 21:10 ` [PULL 08/19] KVM: SEV: Add support to handle MSR based Page State Change VMGEXIT Michael Roth
2024-05-10 21:10 ` [PULL 09/19] KVM: SEV: Add support to handle " Michael Roth
2024-05-12  2:06   ` Michael Roth
2024-05-10 21:10 ` [PULL 10/19] KVM: SEV: Add support to handle RMP nested page faults Michael Roth
2024-05-10 21:10 ` [PULL 11/19] KVM: SEV: Support SEV-SNP AP Creation NAE event Michael Roth
2024-05-10 21:10 ` [PULL 12/19] KVM: SEV: Implement gmem hook for initializing private pages Michael Roth
2024-05-10 21:10 ` [PULL 13/19] KVM: SEV: Implement gmem hook for invalidating " Michael Roth
2024-05-15 22:32   ` Sean Christopherson
2024-05-16  3:11     ` Michael Roth
2024-05-21 16:55       ` Paolo Bonzini
2024-05-16 12:45     ` Paolo Bonzini
2024-05-10 21:10 ` [PULL 14/19] KVM: x86: Implement hook for determining max NPT mapping level Michael Roth
2024-05-10 21:10 ` [PULL 15/19] KVM: SEV: Avoid WBINVD for HVA-based MMU notifications for SNP Michael Roth
2024-05-10 21:10 ` [PULL 16/19] KVM: SVM: Add module parameter to enable SEV-SNP Michael Roth
2024-05-10 21:10 ` [PULL 17/19] KVM: SEV: Provide support for SNP_GUEST_REQUEST NAE event Michael Roth
2024-05-17 20:41   ` Edgecombe, Rick P
2024-05-17 22:01     ` Paolo Bonzini
2024-05-18 15:04       ` [PATCH] KVM: SEV: Fix guest memory leak when handling guest requests Michael Roth
2024-05-20 14:17         ` Sean Christopherson
2024-05-20 22:50           ` Michael Roth
2024-05-20 23:32             ` Sean Christopherson
2024-05-21  2:00               ` Michael Roth
2024-05-21 14:09                 ` Sean Christopherson
2024-05-21 15:34                   ` Michael Roth
2024-05-21 16:58                     ` Sean Christopherson
2024-05-21 21:00                       ` Michael Roth
2024-05-20 23:02         ` Michael Roth [this message]
2024-05-10 21:10 ` [PULL 18/19] KVM: SEV: Provide support for SNP_EXTENDED_GUEST_REQUEST NAE event Michael Roth
2024-05-13 15:19   ` Nathan Chancellor
2024-05-13 16:53     ` Paolo Bonzini
2024-05-13 17:05       ` Michael Roth
2024-05-13 17:20         ` Paolo Bonzini
2024-05-13 21:18         ` Michael Roth
2024-05-10 21:10 ` [PULL 19/19] crypto: ccp: Add the SNP_VLEK_LOAD command Michael Roth
2024-05-12  7:14 ` [PULL 00/19] KVM: Add AMD Secure Nested Paging (SEV-SNP) Hypervisor Support Paolo Bonzini
2024-05-12  8:17   ` Paolo Bonzini
2024-05-13  1:06     ` Michael Roth
2024-05-13 22:08     ` Sean Christopherson
2024-05-31  3:22 ` Michael Roth
2024-06-03 16:44   ` Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240520230200.1161826-1-michael.roth@amd.com \
    --to=michael.roth@amd.com \
    --cc=ashish.kalra@amd.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=rick.p.edgecombe@intel.com \
    --cc=seanjc@google.com \
    --cc=thomas.lendacky@amd.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox