* [PATCH] KVM: nVMX: Re-arm the vmcs12 pages request if mapping the pages fails
@ 2026-08-13 4:39 Jinwoo Lee
2026-08-13 4:57 ` sashiko-bot
2026-08-13 13:43 ` Sean Christopherson
0 siblings, 2 replies; 5+ messages in thread
From: Jinwoo Lee @ 2026-08-13 4:39 UTC (permalink / raw)
To: seanjc, pbonzini; +Cc: kvm, linux-kernel, Jinwoo Lee, stable
Re-arm KVM_REQ_GET_NESTED_STATE_PAGES when nested_get_vmcs12_pages()
fails, so that KVM retries the mapping on the next KVM_RUN instead of
resuming L2 with a stale vmcs02.
On failure KVM exits to userspace with KVM_EXIT_INTERNAL_ERROR but
leaves the vCPU in guest mode with vmcs02 loaded. The request has
already been consumed by kvm_check_request() in vcpu_enter_guest(), and
nothing re-arms it, so a subsequent KVM_RUN goes straight to VM-Enter.
vmcs02's APIC_ACCESS_ADDR, VIRTUAL_APIC_PAGE_ADDR and
POSTED_INTR_DESC_ADDR still hold the host physical addresses that were
mapped for the previous nested VM-Enter. Those pages have already been
unmapped and unpinned by nested_put_vmcs12_pages(), which runs after
vmx_switch_vmcs() to vmcs01 and therefore cannot clear the vmcs02
fields, and prepare_vmcs02_early() re-arms the controls that consume
them without rewriting the address fields. Hardware then accesses
pages that KVM no longer holds a reference to.
The SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES branch makes this worse by
returning before the CPU_BASED_TPR_SHADOW and posted interrupt
fallbacks, which would otherwise write INVALID_GPA to
VIRTUAL_APIC_PAGE_ADDR and clear PIN_BASED_POSTED_INTR.
Commit 671ddc700fd0 ("KVM: nVMX: Don't leak L1 MMIO regions to L2")
replaced the "clear the control" fallback with an error return. The
intent is right, but it left vmcs02 in a usable state. Re-arming the
request closes that; if the mapping keeps failing KVM keeps exiting to
userspace, which is noisy but safe.
Note this relies on KVM_REQ_GET_NESTED_STATE_PAGES being cleared on
nested VM-Exit, which "KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES
is cleared on VM-Exit" makes unconditional.
Fixes: 671ddc700fd0 ("KVM: nVMX: Don't leak L1 MMIO regions to L2")
Cc: stable@vger.kernel.org
Signed-off-by: Jinwoo Lee <rkskek9254@gmail.com>
---
Notes for reviewers, not intended for the commit log.
Affected versions: v5.4-rc5 (671ddc700fd0) through v7.2-rc6. Verified that
nested_get_vmcs12_pages() and the KVM_REQ_GET_NESTED_STATE_PAGES consumer in
vcpu_enter_guest() are unchanged in kvm-x86/next as of 2026-08-13.
Disclosure: this was found with AI-assisted code review, so per
Documentation/process/security-bugs.rst it is being reported publicly rather
than to security@kernel.org.
What I verified empirically, on the RSM path with the load_pdptrs() abort:
- KVM consumes KVM_REQ_GET_NESTED_STATE_PAGES, the mapping fails, KVM_RUN
returns 0 with run->exit_reason left at KVM_EXIT_UNKNOWN, and the vCPU is
still in guest mode.
- The request is not re-armed, and the next KVM_RUN VM-Enters L2, which then
executes with vmcs02 still naming the previously mapped pages. Confirmed
deterministically (4/4) with a selftest, plus a control run showing that
the same sequence without the poison maps successfully.
- With the patch applied the code compiles clean, but I have not been able to
boot a patched kernel, so the fix itself is not runtime tested. The
selftest fails on an unpatched kernel as expected.
What I did not verify:
- The APIC-access branch end to end. That is the interesting one, because it
is reachable by L1 alone (point vmcs12->apic_access_addr at an unbacked
GPA) and it returns before the CPU_BASED_TPR_SHADOW and posted interrupt
fallbacks. This host does not expose
SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES or PIN_BASED_POSTED_INTR to L1, so
I could only reach the load_pdptrs() abort, which needs userspace to poison
the PDPTEs through a KVM_GUESTDBG_SINGLESTEP window and is therefore not
guest-triggerable on its own.
- Whether a stale page is actually reused by the host. The selftest keeps
every page allocated as its own guest RAM for the whole run.
On whether userspace resumes: QEMU's kvm_cpu_exec() treats
KVM_INTERNAL_ERROR_EMULATION as recoverable and returns EXCP_INTERRUPT when
kvm_arch_stop_on_emulation_error() is false, which for x86 is the case when the
guest is in protected mode at CPL 3 (target/i386/kvm/kvm.c). It does not
re-push nested state on that path. This is from reading qemu.git at
055952c0aa91; I have not run it.
A selftest is available. I have not included it here per the reproducer
guidance in security-bugs.rst; happy to post it if you want it.
arch/x86/kvm/vmx/nested.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index ddf6df7bee93..9e9bd6c541ba 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -3453,7 +3453,7 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
* state which can lead to a load of wrong PDPTRs.
*/
if (CC(!load_pdptrs(vcpu, vcpu->arch.cr3)))
- return false;
+ goto fail;
}
@@ -3469,7 +3469,7 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
vcpu->run->internal.suberror =
KVM_INTERNAL_ERROR_EMULATION;
vcpu->run->internal.ndata = 0;
- return false;
+ goto fail;
}
}
@@ -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)
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] KVM: nVMX: Re-arm the vmcs12 pages request if mapping the pages fails
2026-08-13 4:39 [PATCH] KVM: nVMX: Re-arm the vmcs12 pages request if mapping the pages fails Jinwoo Lee
@ 2026-08-13 4:57 ` sashiko-bot
2026-08-13 8:10 ` Jinwoo Lee
2026-08-13 13:43 ` Sean Christopherson
1 sibling, 1 reply; 5+ messages in thread
From: sashiko-bot @ 2026-08-13 4:57 UTC (permalink / raw)
To: Jinwoo Lee; +Cc: kvm
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@gmail.com>
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@gmail.com?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] KVM: nVMX: Re-arm the vmcs12 pages request if mapping the pages fails
2026-08-13 4:57 ` sashiko-bot
@ 2026-08-13 8:10 ` Jinwoo Lee
2026-08-13 13:45 ` Sean Christopherson
0 siblings, 1 reply; 5+ messages in thread
From: Jinwoo Lee @ 2026-08-13 8:10 UTC (permalink / raw)
To: sashiko-reviews, seanjc, pbonzini; +Cc: kvm, linux-kernel, stable
Resending as plain text; the previous copy was rejected by
kvm@vger.kernel.org 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@kernel.org> 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@gmail.com>
>
> 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@gmail.com?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] KVM: nVMX: Re-arm the vmcs12 pages request if mapping the pages fails
2026-08-13 4:39 [PATCH] KVM: nVMX: Re-arm the vmcs12 pages request if mapping the pages fails Jinwoo Lee
2026-08-13 4:57 ` sashiko-bot
@ 2026-08-13 13:43 ` Sean Christopherson
1 sibling, 0 replies; 5+ messages in thread
From: Sean Christopherson @ 2026-08-13 13:43 UTC (permalink / raw)
To: Jinwoo Lee; +Cc: pbonzini, kvm, linux-kernel, stable
On Thu, Aug 13, 2026, Jinwoo Lee wrote:
> Re-arm KVM_REQ_GET_NESTED_STATE_PAGES when nested_get_vmcs12_pages()
> fails, so that KVM retries the mapping on the next KVM_RUN instead of
> resuming L2 with a stale vmcs02.
>
> On failure KVM exits to userspace with KVM_EXIT_INTERNAL_ERROR but
> leaves the vCPU in guest mode with vmcs02 loaded. The request has
> already been consumed by kvm_check_request() in vcpu_enter_guest(), and
> nothing re-arms it, so a subsequent KVM_RUN goes straight to VM-Enter.
>
> vmcs02's APIC_ACCESS_ADDR, VIRTUAL_APIC_PAGE_ADDR and
> POSTED_INTR_DESC_ADDR still hold the host physical addresses that were
> mapped for the previous nested VM-Enter. Those pages have already been
> unmapped and unpinned by nested_put_vmcs12_pages(), which runs after
> vmx_switch_vmcs() to vmcs01 and therefore cannot clear the vmcs02
> fields, and prepare_vmcs02_early() re-arms the controls that consume
> them without rewriting the address fields. Hardware then accesses
> pages that KVM no longer holds a reference to.
>
> The SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES branch makes this worse by
> returning before the CPU_BASED_TPR_SHADOW and posted interrupt
> fallbacks, which would otherwise write INVALID_GPA to
> VIRTUAL_APIC_PAGE_ADDR and clear PIN_BASED_POSTED_INTR.
>
> Commit 671ddc700fd0 ("KVM: nVMX: Don't leak L1 MMIO regions to L2")
> replaced the "clear the control" fallback with an error return. The
> intent is right, but it left vmcs02 in a usable state. Re-arming the
> request closes that; if the mapping keeps failing KVM keeps exiting to
> userspace, which is noisy but safe.
>
> Note this relies on KVM_REQ_GET_NESTED_STATE_PAGES being cleared on
> nested VM-Exit, which "KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES
> is cleared on VM-Exit" makes unconditional.
>
> Fixes: 671ddc700fd0 ("KVM: nVMX: Don't leak L1 MMIO regions to L2")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jinwoo Lee <rkskek9254@gmail.com>
> ---
> Notes for reviewers, not intended for the commit log.
>
> Affected versions: v5.4-rc5 (671ddc700fd0) through v7.2-rc6. Verified that
> nested_get_vmcs12_pages() and the KVM_REQ_GET_NESTED_STATE_PAGES consumer in
> vcpu_enter_guest() are unchanged in kvm-x86/next as of 2026-08-13.
>
> Disclosure: this was found with AI-assisted code review, so per
> Documentation/process/security-bugs.rst it is being reported publicly rather
> than to security@kernel.org.
For the record, IMO that's naive policy that fails to capture the nuance of many
of these bugs. In many cases, finding a KVM bug is very, very different than
fully understanding that a bug can be exploited by a guest. And in my experience,
using AI to find critical bugs requires some amount of expertise, e.g. to generate
targeted prompts, to identify the most interesting reports in the spew of findings,
etc.
> What I verified empirically, on the RSM path with the load_pdptrs() abort:
>
> - KVM consumes KVM_REQ_GET_NESTED_STATE_PAGES, the mapping fails, KVM_RUN
> returns 0 with run->exit_reason left at KVM_EXIT_UNKNOWN, and the vCPU is
> still in guest mode.
> - The request is not re-armed, and the next KVM_RUN VM-Enters L2, which then
> executes with vmcs02 still naming the previously mapped pages. Confirmed
> deterministically (4/4) with a selftest, plus a control run showing that
> the same sequence without the poison maps successfully.
> - With the patch applied the code compiles clean, but I have not been able to
> boot a patched kernel, so the fix itself is not runtime tested. The
> selftest fails on an unpatched kernel as expected.
>
> What I did not verify:
>
> - The APIC-access branch end to end. That is the interesting one, because it
> is reachable by L1 alone (point vmcs12->apic_access_addr at an unbacked
> GPA) and it returns before the CPU_BASED_TPR_SHADOW and posted interrupt
> fallbacks. This host does not expose
> SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES or PIN_BASED_POSTED_INTR to L1, so
> I could only reach the load_pdptrs() abort, which needs userspace to poison
> the PDPTEs through a KVM_GUESTDBG_SINGLESTEP window and is therefore not
> guest-triggerable on its own.
> - Whether a stale page is actually reused by the host. The selftest keeps
> every page allocated as its own guest RAM for the whole run.
>
> On whether userspace resumes: QEMU's kvm_cpu_exec() treats
> KVM_INTERNAL_ERROR_EMULATION as recoverable and returns EXCP_INTERRUPT when
> kvm_arch_stop_on_emulation_error() is false, which for x86 is the case when the
> guest is in protected mode at CPL 3 (target/i386/kvm/kvm.c). It does not
> re-push nested state on that path. This is from reading qemu.git at
> 055952c0aa91; I have not run it.
>
> A selftest is available. I have not included it here per the reproducer
> guidance in security-bugs.rst; happy to post it if you want it.
>
> arch/x86/kvm/vmx/nested.c | 18 ++++++++++++++++--
> 1 file changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index ddf6df7bee93..9e9bd6c541ba 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -3453,7 +3453,7 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
> * state which can lead to a load of wrong PDPTRs.
> */
> if (CC(!load_pdptrs(vcpu, vcpu->arch.cr3)))
> - return false;
> + goto fail;
This error path is broken for other reasons. AFAICT, it doesn't set
vcpu->run->exit_reason, i.e. KVM will exit to userspace with an UNKNOWN exit
reason. svm_get_nested_state_pages() has similar woes (ah, and I see Sashiko
pointed that out as well).
I mentioned that because I think we kill all the birds at the same time (it'll
take more than one stone, but the idiom kinda works?).
E.g. over 2-3 patches, something like:
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 73f37b050d0a..f9090b601efa 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -2125,13 +2125,8 @@ static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)
return false;
}
- if (!nested_svm_merge_msrpm(vcpu)) {
- vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
- vcpu->run->internal.suberror =
- KVM_INTERNAL_ERROR_EMULATION;
- vcpu->run->internal.ndata = 0;
+ if (!nested_svm_merge_msrpm(vcpu))
return false;
- }
if (kvm_hv_verify_vp_assist(vcpu))
return false;
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 7ed79894d11d..2743f37d8bab 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -3458,10 +3458,6 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
} else {
pr_debug_ratelimited("%s: no backing for APIC-access address in vmcs12\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;
}
}
@@ -3532,11 +3528,6 @@ static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
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;
}
#endif
@@ -3906,8 +3897,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
vmentry_failed:
vcpu->arch.nested_run_pending = 0;
- if (status == NVMX_VMENTRY_KVM_INTERNAL_ERROR)
+ if (status == NVMX_VMENTRY_KVM_INTERNAL_ERROR) {
+ vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+ vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
+ vcpu->run->internal.ndata = 0;
return 0;
+ }
if (status == NVMX_VMENTRY_VMEXIT)
return 1;
WARN_ON_ONCE(status != NVMX_VMENTRY_VMFAIL);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e99642acc40d..32401c0b227d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8026,6 +8026,10 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
if (unlikely(!kvm_nested_call(get_nested_state_pages)(vcpu))) {
+ vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+ vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
+ vcpu->run->internal.ndata = 0;
+ kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
r = 0;
goto out;
}
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] KVM: nVMX: Re-arm the vmcs12 pages request if mapping the pages fails
2026-08-13 8:10 ` Jinwoo Lee
@ 2026-08-13 13:45 ` Sean Christopherson
0 siblings, 0 replies; 5+ messages in thread
From: Sean Christopherson @ 2026-08-13 13:45 UTC (permalink / raw)
To: Jinwoo Lee; +Cc: sashiko-reviews, pbonzini, kvm, linux-kernel, stable
On Thu, Aug 13, 2026, Jinwoo Lee wrote:
> 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.
Eh, doesn't really matter. It's still ugly/flawed code that we should fix,
especially since fixing this in a common location should be a net reduction in
code.
> 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.
Heh, which as I pointed out in my other reply, is a bug, not intentional.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-13 13:45 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-13 4:39 [PATCH] KVM: nVMX: Re-arm the vmcs12 pages request if mapping the pages fails Jinwoo Lee
2026-08-13 4:57 ` sashiko-bot
2026-08-13 8:10 ` Jinwoo Lee
2026-08-13 13:45 ` Sean Christopherson
2026-08-13 13:43 ` Sean Christopherson
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.