Severity by source
AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
Race condition requires specific timing interleaving (AC:H); impact limited to spurious WARNING and one wasted VM cycle, interrupt not lost (A:L).
Primary rating from NVD.
CVSS VectorNVD
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
Lifecycle Timeline
5DescriptionNVD
In the Linux kernel, the following vulnerability has been resolved:
KVM: x86: Do IRR scan in __kvm_apic_update_irr even if PIR is empty
Fall back to apic_find_highest_vector() when PID.ON is set but PIR turns out to be empty, to correctly report the highest pending interrupt from the existing IRR.
In a nested VM stress test, the following WARNING fires in vmx_check_nested_events() when kvm_cpu_has_interrupt() reports a pending interrupt but the subsequent kvm_apic_has_interrupt() (which invokes vmx_sync_pir_to_irr() again) returns -1:
WARNING: CPU: 99 PID: 57767 at arch/x86/kvm/vmx/nested.c:4449 vmx_check_nested_events+0x6bf/0x6e0 [kvm_intel] Call Trace: kvm_check_and_inject_events vcpu_enter_guest.constprop.0 vcpu_run kvm_arch_vcpu_ioctl_run kvm_vcpu_ioctl __x64_sys_ioctl do_syscall_64 entry_SYSCALL_64_after_hwframe
The root cause is a race between vmx_sync_pir_to_irr() on the target vCPU and __vmx_deliver_posted_interrupt() on a sender vCPU. The sender performs two individually-atomic operations that are not a single transaction:
- pi_test_and_set_pir(vector) -- sets the PIR bit
- pi_test_and_set_on() -- sets PID.ON
The following interleaving triggers the bug:
Sender vCPU (IPI): Target vCPU (1st sync_pir_to_irr): B1: set PIR[vector] A1: pi_clear_on() A2: pi_harvest_pir() -> sees B1 bit A3: xchg() -> consumes bit, PIR=0 (1st sync returns correct max_irr) B2: set PID.ON = 1
Target vCPU (2nd sync_pir_to_irr): C1: pi_test_on() -> TRUE (from B2) C2: pi_clear_on() -> ON=0 C3: pi_harvest_pir() -> PIR empty C4: *max_irr = -1, early return IRR NOT SCANNED
The interrupt is not lost (it resides in the IRR from the first sync and is recovered on the next vcpu_enter_guest() iteration), but the incorrect max_irr causes a spurious WARNING and a wasted L2 VM-Enter/VM-Exit cycle.
AnalysisAI
KVM/x86 on Linux exposes a race condition in interrupt request register (IRR) scanning that causes incorrect reporting of the highest pending interrupt in nested virtualization scenarios. Specifically, when PID.ON is set by a sender vCPU after the target vCPU has already harvested and cleared the PIR, a second call to vmx_sync_pir_to_irr() observes an empty PIR and returns max_irr=-1 without scanning the IRR, producing a spurious kernel WARNING in vmx_check_nested_events() and a wasted L2 VM-Enter/VM-Exit cycle. The interrupt itself is not lost - it resides in the IRR from the first sync - but the incorrect max_irr triggers the assertion. No public exploit exists and EPSS is 0.02%, consistent with the highly localized, timing-dependent nature of this defect.
Technical ContextAI
The affected code path is KVM's Posted Interrupt Descriptor (PID) mechanism on Intel VMX, used to deliver IPIs between virtual CPUs without exiting to the host. The PIR (Posted Interrupt Requests) bitmap and PID.ON flag are used atomically but in two separate operations: pi_test_and_set_pir() sets the PIR bit first, then pi_test_and_set_on() sets PID.ON. This non-transactional pair creates a TOCTOU-style race window. When a target vCPU calls __kvm_apic_update_irr() via vmx_sync_pir_to_irr(), it may observe PID.ON=1 (set by step 2 of a concurrent sender), clear it, harvest PIR (which is now empty because the previous sync consumed the bit in step 1), and return early with max_irr=-1 without falling back to apic_find_highest_vector() to scan the existing IRR. The CWE is officially listed as N/A, but the root cause class is CWE-362 (Concurrent Execution Using Shared Resource with Improper Synchronization). Affected CPE: cpe:2.3:a:linux:linux.
RemediationAI
Vendor-released patches are available for multiple stable kernel branches. The fixes are committed at https://git.kernel.org/stable/c/bb1703949dcaa9a49c338dee075f659f4634214d (one stable branch), https://git.kernel.org/stable/c/4b6b06a8b12bfd95f9015074b1430c1480908073 (second branch), and https://git.kernel.org/stable/c/33fd0ccd2590b470b65adcca288615ad3b5e3e06 (third branch), targeting 6.18.30, 7.0.7, and 7.1-rc3 respectively. Operators should apply their distribution's next stable kernel update. As a compensating control, disabling nested virtualization (removing 'nested=1' from kvm_intel module parameters or setting /sys/module/kvm_intel/parameters/nested to 0) eliminates the affected code path entirely, at the cost of preventing nested VM workloads. There is no meaningful network-level mitigation since the vulnerability is local.
Same technique Code Injection
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-35161
GHSA-q4rx-hj9c-j8vg