Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Jörg Rödel" <joro@8bytes.org>
Cc: kvm@vger.kernel.org
Subject: Re: [PATCH 4/4] kvm: svm: Support KVM_SEV_SNP_PAGE_TYPE_VMSA at SNP_LAUNCH_UPDATE
Date: Thu, 11 Jun 2026 12:58:49 +0000	[thread overview]
Message-ID: <20260611125849.9ED631F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260611123528.572255-5-joro@8bytes.org>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:

New issues:
- [High] Missing `srcu_read_lock()` when calling `gfn_to_memslot()` in `sev_es_vmsa_pa()`, leading to a potential Use-After-Free of KVM memslots.
- [Low] The local variable `sev_features` in `sev_gmem_post_populate()` is assigned but never used.

Pre-existing issues:
- [Critical] KVM writes firmware data to a potentially read-only userspace page during CPUID error recovery, which could corrupt the global zero page.
- [High] Out-of-order `kunmap_local()` calls violate the highmem API's strict LIFO unmapping requirement.
- [High] A malicious host userspace process can trigger a kernel warning (`WARN_ON_ONCE`) by passing a NULL user address (`uaddr = 0`) when issuing `KVM_SEV_SNP_LAUNCH_UPDATE` for any non-ZERO page type.
--

commit f2475c503a445642b6525297ce3c8dd1d2a1067f
Author: Joerg Roedel <joerg.roedel@amd.com>

kvm: svm: Support KVM_SEV_SNP_PAGE_TYPE_VMSA at SNP_LAUNCH_UPDATE

This commit adds support for setting a VMSA in guest physical memory
during the SEV-SNP launch process. It introduces a new page type,
KVM_SEV_SNP_PAGE_TYPE_VMSA, which is used for the BSP.

> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
> index 0c42af2e62016..52d0fa5ebdab1 100644
> --- a/arch/x86/kvm/svm/sev.c
> +++ b/arch/x86/kvm/svm/sev.c

[ ... ]

> @@ -2532,7 +2546,9 @@ static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
>  	struct sev_gmem_populate_args *sev_populate_args = opaque;
>  	struct sev_data_snp_launch_update fw_args = {0};
>  	struct kvm_sev_info *sev = to_kvm_sev_info(kvm);
> +	gpa_t gpa = gfn << PAGE_SHIFT;
>  	bool assigned = false;
> +	u64 sev_features = 0;
>  	int level;
>  	int ret;

[Severity: Low]
Is the sev_features variable necessary? It gets assigned below when
processing a KVM_SEV_SNP_PAGE_TYPE_VMSA page but doesn't appear to be
used anywhere else in this function.

[ ... ]

> @@ -2550,14 +2566,27 @@ static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
>  	if (src_page) {
>  		void *src_vaddr = kmap_local_page(src_page);
>  		void *dst_vaddr = kmap_local_pfn(pfn);
> +		struct sev_es_save_area *vmsa = dst_vaddr;
> +		bool accept_page = true;
>  
>  		memcpy(dst_vaddr, src_vaddr, PAGE_SIZE);
>  
> +		if (sev_populate_args->type == KVM_SEV_SNP_PAGE_TYPE_VMSA) {
> +			accept_page = snp_check_launch_vmsa(sev, vmsa);
> +			if (accept_page)
> +				sev_features = vmsa->sev_features;
> +		}
>  
>  		kunmap_local(src_vaddr);
>  		kunmap_local(dst_vaddr);

[Severity: High]
This is a pre-existing issue, but does this violate the LIFO unmapping
requirement of the highmem API?

The kmap_local_page() documentation requires mappings to be unmapped in the
exact reverse order. Here src_vaddr is mapped first, then dst_vaddr, but
they are unmapped in the same order instead of reverse. Could this corrupt
the internal stack on the next kmap/kunmap operations?

[ ... ]

> @@ -2593,6 +2622,9 @@ static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
>  		kunmap_local(dst_vaddr);
>  	}
>  
> +	if (ret == 0 && sev_populate_args->type == KVM_SEV_SNP_PAGE_TYPE_VMSA)
> +		sev->initial_vmsa_gpa = gpa;
> +

[Severity: High]
Will this new VMSA initialization path expose a use-after-free of KVM
memslots during launch finish?

By setting sev->initial_vmsa_gpa to a valid page here, the ioctl path
KVM_SEV_SNP_LAUNCH_FINISH can now call sev_es_vmsa_pa(), which looks up the
slot:

arch/x86/kvm/svm/sev.c:sev_es_vmsa_pa() {
    ...
    slot = gfn_to_memslot(vcpu->kvm, gfn);
    ...
}

Since the launch finish ioctl takes kvm->lock and vcpu->mutex, but not
srcu_read_lock(), could a concurrent memslot update swap and free the
memslot before it is accessed in kvm_gmem_get_pfn()?

>  out:
>  	if (ret)
>  		pr_debug("%s: error updating GFN %llx, return code %d (fw_error %d)\n",
> @@ -2620,12 +2652,22 @@ static int snp_launch_update(struct kvm *kvm, struct kvm_sev_cmd *argp)
>  
>  	if (!params.len || !PAGE_ALIGNED(params.len) || params.flags ||
>  	    (params.type != KVM_SEV_SNP_PAGE_TYPE_NORMAL &&
> +	     params.type != KVM_SEV_SNP_PAGE_TYPE_VMSA &&
>  	     params.type != KVM_SEV_SNP_PAGE_TYPE_ZERO &&
>  	     params.type != KVM_SEV_SNP_PAGE_TYPE_UNMEASURED &&
>  	     params.type != KVM_SEV_SNP_PAGE_TYPE_SECRETS &&
>  	     params.type != KVM_SEV_SNP_PAGE_TYPE_CPUID))
>  		return -EINVAL;

[Severity: Critical]
This isn't a bug introduced by this patch, but does the error recovery path
for KVM_SEV_SNP_PAGE_TYPE_CPUID write to a potentially read-only page?

When handling the CPUID type, kvm_gmem_populate() calls get_user_pages_fast()
with gup_flags = 0, requesting read-only access. If userspace mapped a
read-only page like the global zero page, GUP will succeed.

If the firmware returns SEV_RET_INVALID_PARAM, sev_gmem_post_populate() maps
the page with kmap_local_page() and copies the expected values into it:

memcpy(src_vaddr, dst_vaddr, PAGE_SIZE);

Could this illegally overwrite read-only memory and corrupt the global zero
page?

> +	if (params.type == KVM_SEV_SNP_PAGE_TYPE_VMSA) {
> +		/* VMSA page are allowed only once */
> +		if (sev->initial_vmsa_gpa != INVALID_PAGE)
> +			return -EBUSY;
> +		/* Can only deploy a single page as VMSA */
> +		if (params.len != PAGE_SIZE)
> +			return -EINVAL;
> +	}
>  
>  	src = params.type == KVM_SEV_SNP_PAGE_TYPE_ZERO ? NULL : u64_to_user_ptr(params.uaddr);

[Severity: High]
This is a pre-existing issue, but can a host userspace process trigger a
kernel warning by passing a NULL user address (uaddr = 0) here?

If params.uaddr is 0, src becomes NULL and passes the PAGE_ALIGNED(src)
check. kvm_gmem_populate() skips fetching the user page and passes
src_page = NULL to sev_gmem_post_populate().

That function then unconditionally evaluates:

WARN_ON_ONCE(sev_populate_args->type != KVM_SEV_SNP_PAGE_TYPE_ZERO &&
             !src_page)

Since the type isn't ZERO, won't this allow an unprivileged user to spam
the kernel log?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260611123528.572255-1-joro@8bytes.org?part=4

  parent reply	other threads:[~2026-06-11 12:58 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-11 12:35 [PATCH 0/4] KVM: SEV: Support direct setting of VMSA for SEV-SNP guests Jörg Rödel
2026-06-11 12:35 ` [PATCH 1/4] kvm: svm: Streamline VMSA setting for VCPUs Jörg Rödel
2026-06-11 12:56   ` sashiko-bot
2026-06-11 14:13     ` Jörg Rödel
2026-06-11 12:35 ` [PATCH 2/4] kvm: svm: Defer VMSA allocation to LAUNCH_FINISH stage Jörg Rödel
2026-06-11 12:58   ` sashiko-bot
2026-06-11 14:29     ` Jörg Rödel
2026-06-11 12:35 ` [PATCH 3/4] kvm: svm: Support guest-provided VMSA for launching Jörg Rödel
2026-06-11 13:05   ` sashiko-bot
2026-06-11 14:43     ` Jörg Rödel
2026-06-11 12:35 ` [PATCH 4/4] kvm: svm: Support KVM_SEV_SNP_PAGE_TYPE_VMSA at SNP_LAUNCH_UPDATE Jörg Rödel
2026-06-11 12:43   ` Sean Christopherson
2026-06-11 13:23     ` Jörg Rödel
2026-06-11 12:58   ` sashiko-bot [this message]
2026-06-11 15:23     ` Jörg Rödel

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=20260611125849.9ED631F00893@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=joro@8bytes.org \
    --cc=kvm@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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