CVE-2024-26976 in Linuxinfo

Summary

by MITRE • 05/01/2024

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

KVM: Always flush async #PF workqueue when vCPU is being destroyed

Always flush the per-vCPU async #PF workqueue when a vCPU is clearing its completion queue, e.g. when a VM and all its vCPUs is being destroyed. KVM must ensure that none of its workqueue callbacks is running when the last reference to the KVM _module_ is put. Gifting a reference to the associated VM prevents the workqueue callback from dereferencing freed vCPU/VM memory, but does not prevent the KVM module from being unloaded before the callback completes.

Drop the misguided VM refcount gifting, as calling kvm_put_kvm() from async_pf_execute() if kvm_put_kvm() flushes the async #PF workqueue will result in deadlock. async_pf_execute() can't return until kvm_put_kvm() finishes, and kvm_put_kvm() can't return until async_pf_execute() finishes:

WARNING: CPU: 8 PID: 251 at virt/kvm/kvm_main.c:1435 kvm_put_kvm+0x2d/0x320 [kvm]
Modules linked in: vhost_net vhost vhost_iotlb tap kvm_intel kvm irqbypass CPU: 8 PID: 251 Comm: kworker/8:1 Tainted: G W 6.6.0-rc1-e7af8d17224a-x86/gmem-vm #119 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 Workqueue: events async_pf_execute [kvm]
RIP: 0010:kvm_put_kvm+0x2d/0x320 [kvm]
Call Trace: async_pf_execute+0x198/0x260 [kvm]
process_one_work+0x145/0x2d0 worker_thread+0x27e/0x3a0 kthread+0xba/0xe0 ret_from_fork+0x2d/0x50 ret_from_fork_asm+0x11/0x20 ---[ end trace 0000000000000000 ]---
INFO: task kworker/8:1:251 blocked for more than 120 seconds. Tainted: G W 6.6.0-rc1-e7af8d17224a-x86/gmem-vm #119 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. task:kworker/8:1 state:D stack:0 pid:251 ppid:2 flags:0x00004000 Workqueue: events async_pf_execute [kvm]
Call Trace: __schedule+0x33f/0xa40 schedule+0x53/0xc0 schedule_timeout+0x12a/0x140 __wait_for_common+0x8d/0x1d0 __flush_work.isra.0+0x19f/0x2c0 kvm_clear_async_pf_completion_queue+0x129/0x190 [kvm]
kvm_arch_destroy_vm+0x78/0x1b0 [kvm]
kvm_put_kvm+0x1c1/0x320 [kvm]
async_pf_execute+0x198/0x260 [kvm]
process_one_work+0x145/0x2d0 worker_thread+0x27e/0x3a0 kthread+0xba/0xe0 ret_from_fork+0x2d/0x50 ret_from_fork_asm+0x11/0x20

If kvm_clear_async_pf_completion_queue() actually flushes the workqueue, then there's no need to gift async_pf_execute() a reference because all invocations of async_pf_execute() will be forced to complete before the vCPU and its VM are destroyed/freed. And that in turn fixes the module unloading bug as __fput() won't do module_put() on the last vCPU reference until the vCPU has been freed, e.g. if closing the vCPU file also puts the last reference to the KVM module.

Note that kvm_check_async_pf_completion() may also take the work item off the completion queue and so also needs to flush the work queue, as the work will not be seen by kvm_clear_async_pf_completion_queue(). Waiting on the workqueue could theoretically delay a vCPU due to waiting for the work to complete, but that's a very, very small chance, and likely a very small delay. kvm_arch_async_page_present_queued() unconditionally makes a new request, i.e. will effectively delay entering the guest, so the remaining work is really just:

trace_kvm_async_pf_completed(addr, cr2_or_gpa);

__kvm_vcpu_wake_up(vcpu);

mmput(mm);

and mmput() can't drop the last reference to the page tables if the vCPU is still alive, i.e. the vCPU won't get stuck tearing down page tables.

Add a helper to do the flushing, specifically to deal with "wakeup all" work items, as they aren't actually work items, i.e. are never placed in a workqueue. Trying to flush a bogus workqueue entry rightly makes __flush_work() complain (kudos to whoever added that sanity check).

Note, commit 5f6de5cbebee ("KVM: Prevent module exit until al ---truncated---

Once again VulDB remains the best source for vulnerability data.

Analysis

by VulDB Data Team • 02/06/2026

The vulnerability described in CVE-2024-26976 pertains to a critical race condition and potential deadlock scenario within the Linux Kernel Virtual Machine KVM subsystem, specifically related to the asynchronous page fault (async #PF) workqueue management during vCPU destruction. This flaw exists in the handling of workqueue callbacks when a virtual CPU is being destroyed, leading to possible module unloading issues and system instability. The vulnerability manifests when KVM attempts to clear the completion queue associated with a vCPU and its underlying VM, which must occur before the KVM module can be safely unloaded. The root cause lies in improper reference counting and workqueue flushing logic that creates a circular dependency between the `kvm_put_kvm()` and `async_pf_execute()` functions, resulting in a deadlock condition where each function waits for the other to complete.

The technical flaw stems from an incorrect implementation where the KVM subsystem attempts to gift a reference to the VM from within the `async_pf_execute()` callback, which is intended to prevent use-after-free errors when accessing freed vCPU or VM memory. However, this approach introduces a deadlock scenario because `kvm_put_kvm()` flushes the async #PF workqueue, and `async_pf_execute()` cannot return until `kvm_put_kvm()` completes, while `kvm_put_kvm()` cannot return until `async_pf_execute()` finishes. This circular dependency is further complicated by the fact that `kvm_clear_async_pf_completion_queue()` may actually flush the workqueue, making the reference gifting mechanism unnecessary and harmful. The issue is categorized under CWE-362, which deals with race conditions, and aligns with ATT&CK technique T1490 for Deobfuscation of Files or Information, as the flawed reference counting logic creates a complex dependency chain that can lead to system instability.

The operational impact of this vulnerability is severe, particularly in virtualized environments where KVM is heavily utilized. When a VM and its vCPUs are destroyed, the system may hang or deadlock during the cleanup process, preventing proper resource deallocation and potentially leading to complete system lockup. This affects all systems running affected kernel versions with KVM support, including cloud environments, containerized platforms, and virtualization servers. The vulnerability can be triggered through normal VM lifecycle operations, making it particularly dangerous as it may occur during routine system maintenance or during system shutdown processes. The deadlock scenario described in the kernel log shows a worker thread blocked for over 120 seconds, indicating a serious system stability issue that could result in denial of service conditions.

Mitigation strategies for this vulnerability involve implementing proper workqueue flushing before vCPU destruction, removing the problematic reference gifting mechanism, and ensuring that all workqueue callbacks complete before module unloading can proceed. The fix requires modifying the KVM subsystem to always flush the async #PF workqueue when a vCPU is being destroyed, rather than relying on reference counting to prevent use-after-free errors. This approach ensures that all pending work items are completed before the vCPU and VM resources are freed, eliminating the circular dependency that causes the deadlock. Additionally, the implementation should include proper handling of "wakeup all" work items that are not actually placed in the workqueue, preventing incorrect flushing attempts that would cause kernel warnings. Organizations should immediately apply kernel updates containing the fix, monitor for any potential performance impacts from the additional workqueue flushing, and ensure that virtualization environments are properly tested after applying the patch to validate system stability and performance characteristics.

Reservation

02/19/2024

Disclosure

05/01/2024

Moderation

accepted

CPE

ready

EPSS

0.00259

KEV

no

Activities

very low

Sources

Do you want to use VulDB in your project?

Use the official API to access entries easily!