---
id: CVE-2026-99178
title: 'x86/kvm: Don''t consume async #PF flags on a kernel #PF in NMI context'
summary: |-
  In the Linux kernel, the following vulnerability has been resolved:

  x86/kvm: Don't consume async #PF flags on a kernel #PF in NMI context

  An async #PF "page not present" event arrives through the #PF vector,
  and its reason sits in the …
severity: none
vendor: Linux
product: Linux
affected:
  - >-
    Linux >= 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 <
    b77e9622bbade9812e2090c66d25c372f515e921
  - >-
    Linux >= 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 <
    f45ee1ff6358a22d7e22a4c53cb3148ea97b10d9
  - >-
    Linux >= 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 <
    81d99abe2bd81379abfb595e403bbbee6fbfc624
  - Linux < 6.18.59
  - Linux < 7.2.13
  - Linux (all versions)
published: '2026-10-28'
updated: '2026-10-28'
sourceUpdated: '2026-10-28T10:35:31.961Z'
source: CVEORG
sourceUrl: 'https://www.cve.org/CVERecord?id=CVE-2026-99178'
references:
  - url: 'https://git.kernel.org/stable/c/b77e9622bbade9812e2090c66d25c372f515e921'
  - url: 'https://git.kernel.org/stable/c/f45ee1ff6358a22d7e22a4c53cb3148ea97b10d9'
  - url: 'https://git.kernel.org/stable/c/81d99abe2bd81379abfb595e403bbbee6fbfc624'
tags:
  - cve.org
ingestedAt: '2026-10-28T11:09:40.382Z'
---

## Overview

In the Linux kernel, the following vulnerability has been resolved:

x86/kvm: Don't consume async #PF flags on a kernel #PF in NMI context

An async #PF "page not present" event arrives through the #PF vector,
and its reason sits in the per-CPU apf_reason.flags until
__kvm_handle_async_pf() reads and clears it. If an NMI arrives after
the event is injected and before the #PF handler reads the flags, and
the NMI handler itself takes a #PF, that fault reads and clears the
flags belonging to the #PF it interrupted. It then finds interrupts
disabled in the NMI context it interrupted, and panics:

  Kernel panic - not syncing: Host injected async #PF in interrupt
disabled region
  Call Trace:
   <NMI>
   panic+0x52/0x60
   __kvm_handle_async_pf+0xb0/0xb0
   exc_page_fault+0x71/0xb0
   asm_exc_page_fault+0x27/0x30
  RIP: 0010:__get_user_nocheck_8+0x6/0x20
   perf_callchain_user+0x147/0x1a0
   get_perf_callchain+0x12d/0x1c0
   ...
   perf_event_nmi_handler+0x26/0x50
   exc_nmi+0xe8/0x110
  RIP: 0010:asm_exc_page_fault+0x0/0x30
   </NMI>

The last RIP line shows the NMI landing on the first instruction of
the #PF entry. perf with user call chains takes such a fault: the
sampling NMI walks the user stack with __get_user(), which faults when
a saved frame pointer is not a valid user address or the walk runs off
the top of the stack. The same window exists when KVM, running as an
L1 hypervisor with DELIVERY_AS_PF_VMEXIT, reads the flags itself after
a #PF VM-exit.

The NMI entry code saves and restores CR2 for this nesting, but not the
async #PF reason. Andy Lutomirski described the race, with perf as the
example, when async #PF delivery was reworked in 2020 [1]. Saving and
clearing the flags across the NMI, next to CR2, was discussed there but
not merged.

Since that rework, Linux has stopped setting KVM_ASYNC_PF_SEND_ALWAYS,
so the host delivers "page not present" only for user mode faults and
a kernel-mode fault in NMI context (including kernel-mode #MC and #DB)
cannot be an async page fault.  In that case, return without touching
the flags so that the interrupted handler finds them intact.

Tested on v7.3-rc5 in a 4-vCPU, 2 GiB guest restored from a snapshot
whose memory is served on demand through userfaultfd, so that reading
it back takes async #PFs, while every thread samples hardware cycles
with user call chains and points its frame pointer at an unmapped page.
Without this patch the guest panicked as above in 3 of 3 runs. With it,
the guest survived 3 of 3 runs of 60 seconds, and the host counted
148,441 to 153,334 kvm_async_pf_not_present events in the first 20
seconds of each. On 6.18.50 the results were the same: the guest
panicked without the patch and survived with it.

## Affected

- `Linux >= 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 < b77e9622bbade9812e2090c66d25c372f515e921`
- `Linux >= 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 < f45ee1ff6358a22d7e22a4c53cb3148ea97b10d9`
- `Linux >= 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 < 81d99abe2bd81379abfb595e403bbbee6fbfc624`
- `Linux < 6.18.59`
- `Linux < 7.2.13`
- `Linux (all versions)`

## Remediation

Refer to the linked advisories for vendor-supplied fixes and affected version ranges.
