Skip to content

[LTS 9.2] CVE-2026-23401#1357

Merged
PlaidCat merged 1 commit into
ctrliq:ciqlts9_2from
pvts-mat:CVE-2026-23401_ciqlts9_2
Jun 24, 2026
Merged

[LTS 9.2] CVE-2026-23401#1357
PlaidCat merged 1 commit into
ctrliq:ciqlts9_2from
pvts-mat:CVE-2026-23401_ciqlts9_2

Conversation

@pvts-mat

Copy link
Copy Markdown
Contributor

[LTS 9.2]

CVE-2026-23401 VULN-180395

Commits

CVE-2026-23401

KVM: x86/mmu: Drop/zap existing present SPTE even when creating an MMIO SPTE

jira VULN-180395
cve CVE-2026-23401
commit-author Sean Christopherson <seanjc@google.com>
commit aad885e774966e97b675dfe928da164214a71605
upstream-diff Used linux-6.1.y backport
  ed5909992f344a7d3f4024261e9f751d9618a27d for the clean pick. Strictly
  speaking, the upstream's `kvm_flush_remote_tlbs_gfn(vcpu->kvm, gfn,
  level)' call corresponds to LTS 9.2-native
  `kvm_flush_remote_tlbs_with_address(vcpu->kvm, gfn &
  -KVM_PAGES_PER_HPAGE(level), KVM_PAGES_PER_HPAGE(level))'. See the
  non-backported commits:
  - 9ffe9265375cbaf6c01647e31ae9fee8595b698c ("KVM: x86/mmu: Fix wrong gfn
    range of tlb flushing in kvm_set_pte_rmapp()"),
  - 8c63e8c2176552d5c003d7459609383d32bf47f3 ("KVM: x86/mmu: Rename
    kvm_flush_remote_tlbs_with_address()"),
  - c667a3baeddcc982bf512c126aec8d0f04adecfe ("KVM: x86/mmu: Move
    round_gfn_for_level() helper into mmu_internal.h").
  Nevertheless preserved linux-6.1.y's
  `kvm_flush_remote_tlbs_with_address()' call without `gfn' rounding, as
  that's exactly how it's used in the same function a few lines later,
  strongly suggesting that the issues raised in commit 9ffe92653 don't
  apply here.

The KVM module uses different table flushing procedures across time and code space, those relevant to the CVE-2026-23401 fix being:

  • kvm_flush_remote_tlbs_with_range,
  • kvm_flush_remote_tlbs_with_address,
  • kvm_flush_remote_tlbs_range,
  • kvm_flush_remote_tlbs_gfn.

Their evolution can best be presented in the following table, with commits starting from the oldest, up to what can be found in the upstream at the moment of the aad885e fix:

`kernel-mainline` `ciqlts8_6` `ciqlts9_2` `linux-6.1.y` `linux-5.15.y` `kvm_flush_remote_tlbs_with_range` `kvm_flush_remote_tlbs_with_address` `kvm_flush_remote_tlbs_range` `kvm_flush_remote_tlbs_gfn`
40ef75a c4b11c6 40ef75a 40ef75a 40ef75a Defined in `arch/x86/kvm/mmu.c` Defined in `arch/x86/kvm/mmu.c` (calls `kvm_flush_remote_tlbs_with_range`) - -
c50d8ae 94adbae c50d8ae c50d8ae c50d8ae Moved to `arch/x86/kvm/mmu/mmu.c` Moved to `arch/x86/kvm/mmu/mmu.c` - -
2f2fad0 b10939c 2f2fad0 2f2fad0 2f2fad0 0 Made public (non-static) - -
9ffe926 - - - - 0 0 - Definition
28e4b45 - - - - Inlined into `kvm_flush_remote_tlbs_with_address` Inlined the `kvm_flush_remote_tlbs_with_range` call - 0
8c63e8c - - - - - Renamed to `kvm_flush_remote_tlbs_range` Created from `kvm_flush_remote_tlbs_with_address` Change inner call from `kvm_flush_remote_tlbs_with_address` to `kvm_flush_remote_tlbs_range`
9d4655d - - - - - - Changed arg `u64 pages` → `gfn_t nr_pages` 0
d478899 - - - - - - Moved to `virt/kvm/kvm_main.c` and changed body 0

Upstream fix uses:

kvm_flush_remote_tlbs_gfn(vcpu->kvm, gfn, level);

The kvm_flush_remote_tlbs_gfn() function is defined as:

/* Flush the given page (huge or not) of guest memory. */
static inline void kvm_flush_remote_tlbs_gfn(struct kvm *kvm, gfn_t gfn, int level)
{
kvm_flush_remote_tlbs_range(kvm, gfn_round_for_level(gfn, level),
KVM_PAGES_PER_HPAGE(level));
}

The kvm_flush_remote_tlbs_range() call corresponds to kvm_flush_remote_tlbs_with_address() call - the function was renamed in 8c63e8c. The gfn_round_for_level() function is

static inline gfn_t gfn_round_for_level(gfn_t gfn, int level)
{
return gfn & -KVM_PAGES_PER_HPAGE(level);
}

It also exists in LTS 9.2, under a similar name round_gfn_for_level() (moved and renamed in c667a3b).

static gfn_t round_gfn_for_level(gfn_t gfn, int level)
{
return gfn & -KVM_PAGES_PER_HPAGE(level);
}

(It's private, however, so using it in arch/x86/kvm/mmu/mmu.c would require publicizing it (basically what c667a3b does)).

Taking all of the above into account would result in a LTS 9.2-corresponding call:

kvm_flush_remote_tlbs_with_address(vcpu->kvm,
				   gfn & -KVM_PAGES_PER_HPAGE(level),
				   KVM_PAGES_PER_HPAGE(level));

The gfn & -KVM_PAGES_PER_HPAGE(level) part is a rounding of gfn to a value appropriate for kvm_flush_remote_tlbs_with_address() call. Failure to do so in the kvm_set_pte_rmap() function motivated the introduction of kvm_flush_remote_tlbs_gfn() in 9ffe926:

Also introduce a helper function to flush the given
page (huge or not) of guest memory, which would help prevent future
buggy use of kvm_flush_remote_tlbs_with_address() in such case.

The transition from using kvm_flush_remote_tlbs_with_address() to kvm_flush_remote_tlbs_gfn() was done in a few commits: 9ffe926, 1e20384, 1b2dc73, 4ad980a.

However, the CVE-2026-23401-fix-modified function mmu_set_spte() uses kvm_flush_remote_tlbs_with_address() call without gfn rounding just a few lines later

kvm_flush_remote_tlbs_with_address(vcpu->kvm, gfn,
KVM_PAGES_PER_HPAGE(level));

and the transition of this call to kvm_flush_remote_tlbs_gfn() on upstream was done in a non-bugfixing commit 4ad980a. This strongly suggests that gfn is already rounded to the proper value.

Retained the linux-6.1.y solution (aligning also with rocky8_10 fix in 9b906d0) for the sake of simplicity.

kABI check: passed

[0/1] kabi_check_kernel	Check ABI of kernel [ciqlts9_2-CVE-2026-23401]	_kabi_check_kernel__x86_64--test--ciqlts9_2-CVE-2026-23401
+ dist_git_version=el-9.2
+ local_version=ciqlts9_2-CVE-2026-23401
+ arch=x86_64
+ user=pvts
+ buildmachine=x86_64--build--ciqlts9_2
+ virsh_timeout=600
+ ssh_daemon_wait=20
+ src_dir=/mnt/code/kernel-dist-git-el-9.2
+ build_dir=/mnt/build_files/kernel-src-tree-ciqlts9_2-CVE-2026-23401
+ sudo chmod +x /data/src/ctrliq-github-haskell/kernel-dist-git-el-9.2/SOURCES/check-kabi
+ ninja-back/virssh.xsh --max 8 --shutdown-on-success --shutdown-on-failure --timeout 600 --ssh-daemon-wait 20 pvts x86_64--build--ciqlts9_2 ''\''/mnt/code/kernel-dist-git-el-9.2/SOURCES/check-kabi'\'' -k '\''/mnt/code/kernel-dist-git-el-9.2/SOURCES/Module.kabi_x86_64'\'' -s '\''/mnt/build_files/kernel-src-tree-ciqlts9_2-CVE-2026-23401/Module.symvers'\'''
kABI check passed
+ touch state/kernels/ciqlts9_2-CVE-2026-23401/x86_64/kabi_checked

Boot test: passed

boot-test.log

Kselftests: passed relative

Reference

kselftests–ciqlts9_2–run1.log

Patch

kselftests–ciqlts9_2-CVE-2026-23401–run1.log

Comparison

The tests results for the reference and the patch are the same.

$ ktests.xsh diff -d kselftests*.log

Column    File
--------  ----------------------------------------------
Status0   kselftests--ciqlts9_2--run1.log
Status1   kselftests--ciqlts9_2-CVE-2026-23401--run1.log

full-tests-results-comparison.log

…IO SPTE

jira VULN-180395
cve CVE-2026-23401
commit-author Sean Christopherson <seanjc@google.com>
commit aad885e
upstream-diff Used linux-6.1.y backport
  ed5909992f344a7d3f4024261e9f751d9618a27d for the clean pick. Strictly
  speaking, the upstream's `kvm_flush_remote_tlbs_gfn(vcpu->kvm, gfn,
  level)' call corresponds to LTS 9.2-native
  `kvm_flush_remote_tlbs_with_address(vcpu->kvm, gfn &
  -KVM_PAGES_PER_HPAGE(level), KVM_PAGES_PER_HPAGE(level))'. See the
  non-backported commits:
  - 9ffe926 ("KVM: x86/mmu: Fix wrong gfn
    range of tlb flushing in kvm_set_pte_rmapp()"),
  - 8c63e8c ("KVM: x86/mmu: Rename
    kvm_flush_remote_tlbs_with_address()"),
  - c667a3b ("KVM: x86/mmu: Move
    round_gfn_for_level() helper into mmu_internal.h").
  Nevertheless preserved linux-6.1.y's
  `kvm_flush_remote_tlbs_with_address()' call without `gfn' rounding, as
  that's exactly how it's used in the same function a few lines later,
  strongly suggesting that the issues raised in commit 9ffe926 don't
  apply here.

When installing an emulated MMIO SPTE, do so *after* dropping/zapping the
existing SPTE (if it's shadow-present).  While commit a54aa15 was
right about it being impossible to convert a shadow-present SPTE to an
MMIO SPTE due to a _guest_ write, it failed to account for writes to guest
memory that are outside the scope of KVM.

E.g. if host userspace modifies a shadowed gPTE to switch from a memslot
to emulted MMIO and then the guest hits a relevant page fault, KVM will
install the MMIO SPTE without first zapping the shadow-present SPTE.

  ------------[ cut here ]------------
  is_shadow_present_pte(*sptep)
  WARNING: arch/x86/kvm/mmu/mmu.c:484 at mark_mmio_spte+0xb2/0xc0 [kvm], CPU#0: vmx_ept_stale_r/4292
  Modules linked in: kvm_intel kvm irqbypass
  CPU: 0 UID: 1000 PID: 4292 Comm: vmx_ept_stale_r Not tainted 7.0.0-rc2-eafebd2d2ab0-sink-vm ctrliq#319 PREEMPT
  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
  RIP: 0010:mark_mmio_spte+0xb2/0xc0 [kvm]
  Call Trace:
   <TASK>
   mmu_set_spte+0x237/0x440 [kvm]
   ept_page_fault+0x535/0x7f0 [kvm]
   kvm_mmu_do_page_fault+0xee/0x1f0 [kvm]
   kvm_mmu_page_fault+0x8d/0x620 [kvm]
   vmx_handle_exit+0x18c/0x5a0 [kvm_intel]
   kvm_arch_vcpu_ioctl_run+0xc55/0x1c20 [kvm]
   kvm_vcpu_ioctl+0x2d5/0x980 [kvm]
   __x64_sys_ioctl+0x8a/0xd0
   do_syscall_64+0xb5/0x730
   entry_SYSCALL_64_after_hwframe+0x4b/0x53
  RIP: 0033:0x47fa3f
   </TASK>
  ---[ end trace 0000000000000000 ]---

	Reported-by: Alexander Bulekov <bkov@amazon.com>
	Debugged-by: Alexander Bulekov <bkov@amazon.com>
	Suggested-by: Fred Griffoul <fgriffo@amazon.co.uk>
Fixes: a54aa15 ("KVM: x86/mmu: Handle MMIO SPTEs directly in mmu_set_spte()")
	Cc: stable@vger.kernel.org
	Signed-off-by: Sean Christopherson <seanjc@google.com>
(cherry picked from commit ed5909992f344a7d3f4024261e9f751d9618a27d)
	Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
@pvts-mat pvts-mat force-pushed the CVE-2026-23401_ciqlts9_2 branch from 4def139 to 80fc241 Compare June 21, 2026 17:11

@PlaidCat PlaidCat left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@PlaidCat PlaidCat requested a review from a team June 24, 2026 15:38

@bmastbergen bmastbergen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥌

@PlaidCat PlaidCat merged commit 40824e7 into ctrliq:ciqlts9_2 Jun 24, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants