Re: [PATCH] KVM: nVMX: Re-arm the vmcs12 pages request if mapping the pages fails

Jinwoo Lee <[email protected]>
Newsgroups dev.linux.lists.sashiko-reviews,org.kernel.vger.kvm,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <CALz4YMQa4h0oHxrpsiFsPd2qWZO1Q-pE2mbDwvT2wV1b+ukZdg@mail.gmail.com>
Resending as plain text; the previous copy was rejected by
[email protected] because Gmail included an HTML MIME part.  Sorry
for the duplicate on lists that received the first copy.
---
Thanks for the review.

> This is a pre-existing issue, but should the same re-arm be applied to
> vmx_get_nested_state_pages() and svm_get_nested_state_pages()?

At the request-lifetime level, yes.  kvm_check_request() consumes
KVM_REQ_GET_NESTED_STATE_PAGES before get_nested_state_pages() is called.
If the callback returns false, the request needs to remain pending;
otherwise a later KVM_RUN can skip the deferred setup.

On further inspection, re-arming the request in
nested_get_vmcs12_pages() is too low-level.  That helper is also called
directly from the normal nested VM-Entry path, before enter_guest_mode(),
and that caller switches back to vmcs01 if the helper fails.  I will move
the retry to the KVM_REQ_GET_NESTED_STATE_PAGES consumption path in
vcpu_enter_guest(), or to an equivalent wrapper, so that the request is
re-armed only after it was actually consumed.  That will also cover
failures returned by both the VMX and SVM get_nested_state_pages()
callbacks.

The eVMCS path needs additional handling beyond a generic re-arm.
nested_vmx_handle_enlightened_vmptrld() releases the old eVMCS mapping
before attempting to map the new GPA.  If kvm_vcpu_map() fails,
hv_evmcs_vmptr is left as EVMPTR_INVALID, whereas
nested_get_evmcs_page() retries the mapping only when hv_evmcs_vmptr is
EVMPTR_MAP_PENDING.  Re-arming the request alone would therefore not
necessarily retry the failed eVMCS mapping.  I will preserve or restore
a retryable eVMCS state on that failure path in v2.

For SVM, I agree that failures in load_pdptrs(),
nested_svm_merge_msrpm(), and kvm_hv_verify_vp_assist() can lose the
consumed request, and that L2 must not resume until the deferred setup
has completed successfully.

However, I do not currently see evidence that the SVM failures have the
same unpinned-HPA/UAF mechanism as the nVMX APIC-backed VMCS02 fields.
In particular, nested_vmcb02_prepare_control() initially copies
vmcb01's KVM-owned MSRPM address into vmcb02, and
nested_svm_merge_msrpm() switches vmcb02 to the KVM-owned merged MSRPM
only after the merge completes successfully.  Losing the request after
a failed merge can therefore allow L2 to run without L1's complete MSR
intercept state, but it does not appear to leave hardware pointing at an
unpinned guest page.  I will describe and test the SVM impact separately
instead of treating it as the same UAF without supporting evidence.

> Does this allow L2 to resume with unpinned HPAs and lead to a
> use-after-free?

Not uniformly across these paths.  The unpinned-HPA mechanism is the
concern for the nVMX VMCS02 address fields described in the patch, but I
have not yet reproduced host-page reuse or an actual use-after-free end
to end.  For eVMCS and SVM, the current evidence establishes that the
deferred setup request can be lost; it does not yet establish the same
unpinned-HPA mechanism.

I will also correct the commit message.  Not every failure reports
KVM_EXIT_INTERNAL_ERROR: the load_pdptrs() failure used by my RSM
reproducer returns with exit_reason unchanged, which is
KVM_EXIT_UNKNOWN in the test.

I will rework the patch and selftest accordingly and runtime-test the
fix before posting v2.

Thanks,
Jinwoo


On Thu, Aug 13, 2026 at 1:57 PM <[email protected]> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] The patch fixes the missing re-arming of `KVM_REQ_GET_NESTED_STATE_PAGES` in `nested_get_vmcs12_pages()` for VMX but overlooks identical vulnerabilities in `vmx_get_nested_state_pages()` (VMX eVMCS) and `svm_get_nested_state_pages()` (SVM).
> --
>
> --- Patch [1]: [PATCH] KVM: nVMX: Re-arm the vmcs12 pages request if mapping the pages fails ---
> commit ce93ee9654c7f639f51372bb8a7e1b25a376436b
> Author: Jinwoo Lee <[email protected]>
>
> KVM: nVMX: Re-arm the vmcs12 pages request if mapping the pages fails
>
> This commit ensures KVM_REQ_GET_NESTED_STATE_PAGES is re-armed if
> nested_get_vmcs12_pages() fails to map the pages. This forces KVM to retry the
> mapping on the next KVM_RUN rather than resuming L2 with a stale vmcs02, which
> prevents hardware from accessing unpinned host physical pages.
>
> > diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> > index ddf6df7bee93b..9e9bd6c541baa 100644
> > --- a/arch/x86/kvm/vmx/nested.c
> > +++ b/arch/x86/kvm/vmx/nested.c
> [ ... ]
> > @@ -3525,6 +3525,20 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
> >               exec_controls_clearbit(vmx, CPU_BASED_USE_MSR_BITMAPS);
> >
> >       return true;
> > +
> > +fail:
> > +     /*
> > +      * Re-arm the request so that KVM retries the mapping instead of running
> > +      * L2 with a stale vmcs02.  Bailing here leaves the vCPU in guest mode
> > +      * with vmcs02 loaded and its APIC-access, virtual-APIC and posted
> > +      * interrupt descriptor addresses still pointing at the host pages that
> > +      * were mapped for the *previous* nested VM-Enter, which have since been
> > +      * unmapped and unpinned by nested_put_vmcs12_pages().  KVM returns to
> > +      * userspace without leaving guest mode, so if userspace resumes the
> > +      * vCPU, VM-Enter succeeds and hardware accesses those stale HPAs.
> > +      */
> > +     kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
> > +     return false;
> >  }
> >
> >  static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
>
> [Severity: High]
> This is a pre-existing issue, but should the same re-arm be applied to
> vmx_get_nested_state_pages() and svm_get_nested_state_pages()?
>
> If nested_get_evmcs_page() fails in vmx_get_nested_state_pages(), it returns
> false and exits to userspace with KVM_EXIT_INTERNAL_ERROR without re-arming
> the request:
>
> arch/x86/kvm/vmx/nested.c:vmx_get_nested_state_pages() {
>         if (!nested_get_evmcs_page(vcpu)) {
>                 pr_debug_ratelimited("%s: enlightened vmptrld failed\n",
>                                      __func__);
>                 vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
>                 vcpu->run->internal.suberror =
>                         KVM_INTERNAL_ERROR_EMULATION;
>                 vcpu->run->internal.ndata = 0;
>
>                 return false;
>         }
>     ...
> }
>
> Similarly, in arch/x86/kvm/svm/nested.c:svm_get_nested_state_pages(), if
> load_pdptrs(), kvm_hv_verify_vp_assist(), or nested_svm_merge_msrpm() fail,
> they also exit without re-arming.
>
> If a compromised QEMU sets KVM_REQ_GET_NESTED_STATE_PAGES and KVM clears the
> request but fails in these setup steps, a subsequent KVM_RUN could skip state
> setup and proceed directly to VM-Enter L2 with stale control structures.
>
> Does this allow L2 to resume with unpinned HPAs and lead to a use-after-free?
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.