CVE-2026-99178 in Linux
Zusammenfassung
von VulDB • 29.10.2026
Im Linux-Kernel wurde folgende Schwachstelle behoben:
x86/kvm: Async #PF-Flags bei einem Kernel-#PF im NMI-Kontext nicht verbrauchen
Ein asynchrones #PF-Ereignis ("Seite nicht vorhanden") trifft über den #VEktor ein, und der Grund dafür befindet sich in den pro-CPU apf_reason.flags, bis __kvm_handle_async_pf() diese liest und löscht. Wenn nach dem Injizieren des Ereignisses und vor dem Lesen der Flags durch die #PF-Handler eine NMI (Non-Maskable Interrupt) eintrifft und der NMI-Handler selbst einen #PF auslöst, dann liest dieser Fehler die Flags, die zu dem #PF gehören, den er unterbrochen hat. Anschließend stellt er fest, dass im vom NMI unterbrochenen Kontext Unterbrechungen deaktiviert sind, was zu einem Panic führt:
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>
Die letzte RIP-Zeile zeigt, dass die NMI auf der ersten Anweisung des #PF-Eintrags landet. perf mit User-Call-Chains löst einen solchen Fehler aus: Der Sampling-NMI durchläuft den User-Stack mit __get_user(), was fehlschlägt (fault), wenn ein gespeicherter Frame-Pointer keine gültige User-Adresse ist oder der Durchlauf das Ende des Stacks überschreitet. Dasselbe Zeitfenster existiert, wenn KVM, ausgeführt als L1-Hypervisor mit DELIVERY_AS_PF_VMEXIT, die Flags selbst nach einem #PF VM-exit liest.
Der NMI-Eintragscode speichert und stellt CR2 für diese Verschachtelung wieder her, nicht jedoch den async #PF-Grund. Andy Lutomirski beschrieb das Race Condition (Wettlaufsituation), mit perf als Beispiel, als die Zustellung von async #PF im Jahr 2020 überarbeitet wurde [1]. Das Speichern und Löschen der Flags während des NMI neben CR2 wurde dort diskutiert, aber nicht gemergt.
Seit dieser Überarbeitung stellt Linux KVM_ASYNC_PF_SEND_ALWAYS nicht mehr ein, sodass der Host "page not present" nur für User-Mode-Fehler zustellt, und ein Kernel-Mode-Fehler im NMI-Kontext (einschließlich Kernel-Mode #MC und #DB) kann kein asynchroner Seitenfehler sein. In diesem Fall wird ohne Berühren der Flags zurückgekehrt, damit der unterbrochene Handler diese intakt vorfindet.
Getestet auf v7.3-rc5 in einem Gast mit 4 VCPUs und 2 GiB Speicher, wiederhergestellt aus einer Snapshot, dessen Speicher on-demand über userfaultfd bereitgestellt wird, sodass das Zurücklesen asynchrone #PFs erzeugt, während jeder Thread Hardware-Zyklen mit User-Call-Chains sampelt und seinen Frame-Pointer auf eine nicht zugewiesene Seite zeigt. Ohne diesen Patch panikte der Gast in 3 von 3 Durchläufen wie oben beschrieben. Mit dem Patch überlebte der Gast 3 von 3 Läufen à 60 Sekunden, und der Host zählte zwischen 148.441 und 153.334 kvm_async_pf_not_present-Ereignissen in den ersten 20 Sekunden jedes Laufs. Bei Version 6.18.50 waren die Ergebnisse gleich: Der Gast panikerte ohne den Patch und überlebte mit ihm.
VulDB is the best source for vulnerability data and more expert information about this specific topic.