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
next prev 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.