GHSA-97Q3-WCM5-M49Q
Vulnerability from github – Published: 2026-09-24 18:31 – Updated: 2026-09-25 06:30In the Linux kernel, the following vulnerability has been resolved:
virt: acrn: Fix irqfd use-after-free during eventfd shutdown
acrn_irqfd_deassign() and the eventfd EPOLLHUP wakeup can race and free the same struct hsm_irqfd:
CPU0 CPU1 ---- ---- eventfd_release() wake_up_poll(EPOLLHUP) hsm_irqfd_wakeup() queue_work(&irqfd->shutdown) acrn_irqfd_deassign() hsm_irqfd_shutdown() list_del_init() eventfd_ctx_remove_wait_queue() eventfd_ctx_put() kfree(irqfd) hsm_irqfd_shutdown_work() container_of(work, ..., shutdown) irqfd->vm <-- use-after-free
The deassign path freed the irqfd while a shutdown work item was already queued by EPOLLHUP (or vice versa), so the work item could resurrect a dangling pointer through container_of().
Switch to the lifetime model used by KVM irqfds:
- Deassign/deinit only deactivate the irqfd: remove it from vm->irqfds under irqfds_lock and queue the cleanup work.
- hsm_irqfd_shutdown_work() becomes the sole owner that unhooks the eventfd waitqueue entry, drops the eventfd reference and frees the irqfd.
- A new HSM_IRQFD_FLAG_SHUTDOWN bit guarded by test_and_set_bit() ensures the cleanup work is queued at most once, no matter how many of {EPOLLHUP, deassign, deinit} fire concurrently. This is safe to call from the waitqueue callback, which runs with wqh->lock held and IRQs disabled and therefore cannot take irqfds_lock.
- acrn_irqfd_deassign() flushes vm->irqfd_wq before returning so the eventfd is fully detached on return. acrn_irqfd_deinit() deactivates every irqfd, flushes the workqueue and only then destroys it, so no path can queue_work() onto a torn-down workqueue.
- acrn_irqfd_assign() now installs the eventfd waitqueue entry and publishes the irqfd to vm->irqfds under irqfds_lock, so the irqfd is never visible to deassign/deinit before its waitqueue entry is in place, and any EPOLLHUP that fires in the assign window queues cleanup work that blocks on irqfds_lock until publication is done.
{
"affected": [],
"aliases": [
"CVE-2026-97478"
],
"database_specific": {
"cwe_ids": [],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-09-24T17:17:25Z",
"severity": "HIGH"
},
"details": "In the Linux kernel, the following vulnerability has been resolved:\n\nvirt: acrn: Fix irqfd use-after-free during eventfd shutdown\n\nacrn_irqfd_deassign() and the eventfd EPOLLHUP wakeup can race and free\nthe same struct hsm_irqfd:\n\n CPU0 CPU1\n ---- ----\n eventfd_release()\n wake_up_poll(EPOLLHUP)\n hsm_irqfd_wakeup()\n queue_work(\u0026irqfd-\u003eshutdown)\n acrn_irqfd_deassign()\n hsm_irqfd_shutdown()\n list_del_init()\n eventfd_ctx_remove_wait_queue()\n eventfd_ctx_put()\n kfree(irqfd)\n hsm_irqfd_shutdown_work()\n container_of(work, ..., shutdown)\n irqfd-\u003evm \u003c-- use-after-free\n\nThe deassign path freed the irqfd while a shutdown work item was\nalready queued by EPOLLHUP (or vice versa), so the work item could\nresurrect a dangling pointer through container_of().\n\nSwitch to the lifetime model used by KVM irqfds:\n\n - Deassign/deinit only deactivate the irqfd: remove it from vm-\u003eirqfds\n under irqfds_lock and queue the cleanup work.\n - hsm_irqfd_shutdown_work() becomes the sole owner that unhooks the\n eventfd waitqueue entry, drops the eventfd reference and frees the\n irqfd.\n - A new HSM_IRQFD_FLAG_SHUTDOWN bit guarded by test_and_set_bit()\n ensures the cleanup work is queued at most once, no matter how many\n of {EPOLLHUP, deassign, deinit} fire concurrently. This is safe to\n call from the waitqueue callback, which runs with wqh-\u003elock held and\n IRQs disabled and therefore cannot take irqfds_lock.\n - acrn_irqfd_deassign() flushes vm-\u003eirqfd_wq before returning so the\n eventfd is fully detached on return. acrn_irqfd_deinit() deactivates\n every irqfd, flushes the workqueue and only then destroys it, so no\n path can queue_work() onto a torn-down workqueue.\n - acrn_irqfd_assign() now installs the eventfd waitqueue entry and\n publishes the irqfd to vm-\u003eirqfds under irqfds_lock, so the irqfd is\n never visible to deassign/deinit before its waitqueue entry is in\n place, and any EPOLLHUP that fires in the assign window queues\n cleanup work that blocks on irqfds_lock until publication is done.",
"id": "GHSA-97q3-wcm5-m49q",
"modified": "2026-09-25T06:30:31Z",
"published": "2026-09-24T18:31:34Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-97478"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/666c7f9e07925aa0863348f960e09bb89f8f05a3"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/d8156aacfcabb81f52c20ef89094945434d08079"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.