public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: punixcorn <ohyunwoods663@gmail.com>
Cc: pbonzini@redhat.com, kvm@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [BUG] KVM: NULL pointer dereference in kvm_tdp_mmu_map under memory pressure
Date: Wed, 8 Apr 2026 07:18:27 -0700	[thread overview]
Message-ID: <adZjswAhbcQmekxZ@google.com> (raw)
In-Reply-To: <20260408102914.106838-1-ohyunwoods663@gmail.com>

On Wed, Apr 08, 2026, punixcorn wrote:
> Under host memory pressure, a NULL pointer dereference occurs in
> kvm_tdp_mmu_map() at offset 0x24. The exact root cause is unclear --
> it may be an unhandled NULL return from tdp_mmu_alloc_sp(), or a
> violated invariant elsewhere in the map path.

It's pretty much guaranteed to be the latter.

tdp_mmu_alloc_sp() can't fail, as KVM ensures vcpu->arch.mmu_page_header_cache
holds enough pre-allocated entries to service the page fault.  Even if that
invariant fails and KVM exhausts the cache, it should still be impossible for
kvm_mmu_memory_cache_alloc() to return NULL because it will either use a fallback
allocation (after WARNing) and succeed, or BUG_ON() and prevent hitting the NULL
pointer deref.

  void *kvm_mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc)
  {
	void *p;

	if (WARN_ON(!mc->nobjs))
		p = mmu_memory_cache_alloc_obj(mc, GFP_ATOMIC | __GFP_ACCOUNT);
	else
		p = mc->objects[--mc->nobjs];
	BUG_ON(!p);
	return p;
  }

And even if _that_ didn't suffice, tdp_mmu_alloc_sp() itself deferences the
return sp, so the NULL pointer deref would happen earlier.

  static struct kvm_mmu_page *tdp_mmu_alloc_sp(struct kvm_vcpu *vcpu)
  {
	struct kvm_mmu_page *sp;

	sp = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache);
	sp->spt = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_shadow_page_cache);

	return sp;
  }

> 
> Crash log:
> 
>   BUG: kernel NULL pointer dereference, address: 0000000000000024
>   #PF: supervisor read access in kernel mode
>   Oops: 0000 [#1] SMP NOPTI
>   CPU: 2 PID: 1110212 Comm: MainLoopThread Tainted: G U OE 6.19.10-arch1-1
>   Hardware name: Default Default/NLXB, BIOS BQ141 06/27/2024
>   RIP: 0010:kvm_tdp_mmu_map+0x471/0x880 [kvm]
>   Code: 00 00 00 80 48 2b 35 76 72 5c c8 48 c7 44 24 20 00 00 00 00 48 01 f1 48 c1 e9 0c 48 c1 e1 06 48 03 0d 4b 72 5c c8 48 8b 71 28 <0f> b6 4e 24 83 e1 0f 39 ca 0f 85 a7 02 00 00 f6 c4 08 74 26 80 7b
>   RSP: 0018:ffffce128333f790 EFLAGS: 00010286

As noted in your response, I'm 99% certain this is the first derefence of the
shadow page in tdp_mmu_map_handle_target_level():

  static int tdp_mmu_map_handle_target_level(struct kvm_vcpu *vcpu,
 					  struct kvm_page_fault *fault,
					  struct tdp_iter *iter)
  {
	struct kvm_mmu_page *sp = sptep_to_sp(rcu_dereference(iter->sptep));
	u64 new_spte;
	int ret = RET_PF_FIXED;
	bool wrprot = false;

	if (WARN_ON_ONCE(sp->role.level != fault->goal_level))  <============= "sp" is NULL
		return RET_PF_RETRY;


The code stream lines up with that on my builds, and "role" is at offset 0x24.

I can think of three possible sources of failure:

  1. KVM installed a non-leaf SPTE without doing set_page_private().
  2. iter->sptep is corrupted/garbage.
  3. iter->sptep points at a freed shadow page, i.e. page->private was nullified
     due to the page being freed and/or re-allocated.

#1 seems unlikely as I wouldn't expect such a bug to manifest intermittently; the
code is pretty fixed/straightforward.

#2 isn't very likely either, given that it's dereferencing the shadow page that
fails.  I.e. KVM did _not_ fail grabbing the shadow page from iter->sptep, then
iter->sptep isn't complete garbage.  But it's still a possibility, e.g. if sptep
is garbage but happens to still point at a valid struct page.

#3 is the most likely option; as it would "just" require a violation of RCU
protection somewhere.

Can you run with this as a debug patch?  With luck, the output will provide some
hint as to what's going wrong.

diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
index 7b1102d26f9c..0332faf8ef9a 100644
--- a/arch/x86/kvm/mmu/tdp_mmu.c
+++ b/arch/x86/kvm/mmu/tdp_mmu.c
@@ -1174,6 +1174,17 @@ static int tdp_mmu_map_handle_target_level(struct kvm_vcpu *vcpu,
        int ret = RET_PF_FIXED;
        bool wrprot = false;
 
+       if (WARN_ON_ONCE(!sp)) {
+               pr_warn("NULL sp.  sptep = %lx, spte = %llx, pt[0] = %lx, pt[1] = %lx, pt[2] = %lx, pt[3] = %lx, pt[4] = %lx\n",
+                       (unsigned long)iter->sptep, iter->old_spte,
+                       (unsigned long)iter->pt_path[0],
+                       (unsigned long)iter->pt_path[1],
+                       (unsigned long)iter->pt_path[2],
+                       (unsigned long)iter->pt_path[3],
+                       (unsigned long)iter->pt_path[4]);
+               return RET_PF_RETRY;
+       }
+
        if (WARN_ON_ONCE(sp->role.level != fault->goal_level))
                return RET_PF_RETRY;
 


> Reproduction:
> 
> The issue was observed under heavy host memory pressure while running
> a KVM guest (Android emulator via QEMU).

Can you elaborate on the environment?  Specifically, what is your host setup?
E.g. CPU and platform info, and your .config.

> This has not been fully verified. Sending for maintainer review.
> 
> Environment:
>   Linux 6.19.10-arch1-1 x86_64
>   GNU C 15.2.1
>   Binutils 2.46
> 
> Signed-off-by: punixcorn <ohyunwoods663@gmail.com>

  parent reply	other threads:[~2026-04-08 14:18 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-08 10:29 [BUG] KVM: NULL pointer dereference in kvm_tdp_mmu_map under memory pressure punixcorn
2026-04-08 11:21 ` punixcorn
2026-04-08 14:18 ` Sean Christopherson [this message]
     [not found] <202604081418.sean.christopherson@intel.com>
2026-04-08 15:36 ` punixcorn
2026-04-08 16:33   ` Sean Christopherson
     [not found] <202604081633.sean.christopherson@intel.com>
2026-04-08 18:43 ` punixcorn

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=adZjswAhbcQmekxZ@google.com \
    --to=seanjc@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ohyunwoods663@gmail.com \
    --cc=pbonzini@redhat.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