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

From: Jinwoo Lee

Date: Thu Aug 13 2026 - 04:10:52 EST


Resending as plain text; the previous copy was rejected by
kvm@xxxxxxxxxxxxxxx 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 <sashiko-bot@xxxxxxxxxx> 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 <rkskek9254@xxxxxxxxx>
>
> 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/20260813043932.3214460-1-rkskek9254@xxxxxxxxx?part=1