mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Mushahid Hussain <hmushi@amazon.co.uk>
To: Sean Christopherson <seanjc@google.com>,
	Paolo Bonzini <pbonzini@redhat.com>
Cc: <kvm@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<nh-open-source@amazon.com>, <mushi.shar@gmail.com>
Subject: [PATCH] KVM: x86/mmu: Fail nested EPT walks for GPAs beyond the EPT width
Date: Mon, 5 Oct 2026 19:20:10 +0000	[thread overview]
Message-ID: <20261005192010.66037-1-hmushi@amazon.co.uk> (raw)

Fail the nested EPT walk when the L2 guest-physical address has bits
above the width of L1's EPT. The width is 48 bits for a 4-level EPT
and 57 bits for a 5-level EPT. Report no RWX bits in the exit
qualification, as for a translation that no table entry provides. L1
then handles the EPT violation itself.

Hardware signals an EPT violation for such an address without a table
walk. KVM's shadow walker instead indexes the tables with PT_INDEX(),
which drops the high bits. The walk resolves the aliased address and
KVM installs a shadow mapping for the alias. The CPU faults on the
original address again, and KVM repeats the walk without end. L1 does
not see an EPT violation for the access, and the L2 vCPU is stuck.

Any L2 that references an address at or above 2^48 under a 4-level
EPT triggers the hang. The easy way to get there is a MAXPHYADDR that
differs between L1 and the host. Take L1 MAXPHYADDR 48 on a 52-bit
host with KVM's default allow_smaller_maxphyaddr=0. A PTE bit that L1
treats as reserved is then valid for the CPU. kvm-unit-tests "access"
and "vmx_pf_exception_test", run as L2 under an L1 KVM with MAXPHYADDR
48, hang at the first present PTE with bit 51 set.

Fixes: 37406aaaeebc ("nEPT: Add EPT tables support to paging_tmpl.h")
Assisted-by: Claude:claude-fable-5.1
Signed-off-by: Mushahid Hussain <hmushi@amazon.co.uk>
---
Reproducer:
  L1: KVM, CPUID MAXPHYADDR 48, 4-level EPT.
  Host: 52-bit MAXPHYADDR, allow_smaller_maxphyaddr=0.
  L2: kvm-unit-tests "access" and "vmx_pf_exception_test" under QEMU.
      Both set a PTE with bit 51, which L1 treats as reserved and the
      CPU treats as an address bit.

Without the patch both tests hang at the first such PTE. L1 sees no
EPT violation.

With the patch L1 receives the EPT violation. Both tests pass with the
bit-51 cases excluded, as access.c does for MAXPHYADDR >= 52. This holds
with ept=1 and ept=0.

 arch/x86/kvm/mmu/paging_tmpl.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h
index 8e350095508c5..6ba4439e56b10 100644
--- a/arch/x86/kvm/mmu/paging_tmpl.h
+++ b/arch/x86/kvm/mmu/paging_tmpl.h
@@ -378,6 +378,21 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
 	    KVM_BUG_ON(walker->max_level > PT_MAX_FULL_LEVELS, vcpu->kvm))
 		goto error;
 
+#if PTTYPE == PTTYPE_EPT
+	/*
+	 * EPT translates 48-bit guest-physical addresses with 4-level tables
+	 * and 57-bit ones with 5-level tables; hardware raises an EPT
+	 * violation for an address with bits above that width without
+	 * consulting the tables.  PT_INDEX() drops those bits, so walking
+	 * would resolve the aliased address and the shadow mapping built for
+	 * it can never satisfy the CPU.  Fail the walk the way hardware does.
+	 */
+	if (unlikely(addr >> (PAGE_SHIFT + walker->level * PT_LEVEL_BITS))) {
+		pte_access = 0;
+		goto error;
+	}
+#endif
+
 	++walker->level;
 
 	do {

base-commit: 6bd2905303c58679e303941b7d8ae8c074cd95ce
-- 
2.47.3


             reply	other threads:[~2026-10-05 19:20 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-05 19:20 Mushahid Hussain [this message]
2026-10-06  5:23 ` Sean Christopherson

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=20261005192010.66037-1-hmushi@amazon.co.uk \
    --to=hmushi@amazon.co.uk \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mushi.shar@gmail.com \
    --cc=nh-open-source@amazon.com \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    /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

all inboxes | Powered by JetHome®