Skip to content
Heist/ feed
Back to feed
UnratedFix available

vhost-vdpa: protect config_ctx from being freed under the config callback

Type: advisorySources: OSV

In the Linux kernel, the following vulnerability has been resolved: vhost-vdpa: protect config_ctx from being freed under the config callback vhost_vdpa_config_cb() loads v->config_ctx and signals it without taking a reference and without holding any lock: struct eventfd_ctx *config_ctx = v->config_ctx; if (config_ctx) eventfd_signal(config_ctx); VHOST_VDPA_SET_CONFIG_CALL replaces that field and drops what is normally the last reference to the old context: swap(ctx, v->config_ctx); if (ctx) eventfd_ctx_put(ctx); eventfd_ctx_put() drops the last kref and frees the context immediately, with no RCU grace period, so a callback that has already loaded the pointer goes on to dereference freed memory. The two sides share no lock: the ioctl runs under vhost_dev.mutex, while the parent invokes the callback from its own interrupt or workqueue context. This is not the reopen refcount underflow fixed by commit f6bbf0010ba0 ("vhost-vdpa: fix use-after-free of v->config_ctx"), which was about vhost_vdpa_config_put() leaving a stale pointer behind. Here the pointer is maintained correctly and it is the read side that is unprotected. With VDUSE as the parent this is reachable from userspace with access to /dev/vduse (root by default). VDUSE_DEV_INJECT_CONFIG_IRQ queues dev->inject, and vduse_dev_irq_inject() runs the callback under VDUSE's own dev->irq_lock, which vhost does not hold. vduse_dev_reset() does flush_work(&dev->inject), but VHOST_VDPA_SET_CONFIG_CALL never goes through reset, s

Products
Kernel
Affected versions
Not specified
Fixed versions
6.12.111, 6.18.53, 6.6.160, 7.2.7
CVEs
CVE-2026-97992
Confirmed fixed CVEs
Not specified
Updated in this feed
2 Nov 2026, 21:31 UTC · Revision 1

Source evidence

vhost-vdpa: protect config_ctx from being freed under the config callback

core-osv · Original source

Published 25 Sept 2026, 10:23 UTC

In the Linux kernel, the following vulnerability has been resolved: vhost-vdpa: protect config_ctx from being freed under the config callback vhost_vdpa_config_cb() loads v->config_ctx and signals it without taking a reference and without holding any lock: struct eventfd_ctx *config_ctx = v->config_ctx; if (config_ctx) eventfd_signal(config_ctx); VHOST_VDPA_SET_CONFIG_CALL replaces that field and drops what is normally the last reference to the old context: swap(ctx, v->config_ctx); if (ctx) eventfd_ctx_put(ctx); eventfd_ctx_put() drops the last kref and frees the context immediately, with no RCU grace period, so a callback that has already loaded the pointer goes on to dereference freed memory. The two sides share no lock: the ioctl runs under vhost_dev.mutex, while the parent invokes the callback from its own interrupt or workqueue context. This is not the reopen refcount underflow fixed by commit f6bbf0010ba0 ("vhost-vdpa: fix use-after-free of v->config_ctx"), which was about vhost_vdpa_config_put() leaving a stale pointer behind. Here the pointer is maintained correctly and it is the read side that is unprotected. With VDUSE as the parent this is reachable from userspace with access to /dev/vduse (root by default). VDUSE_DEV_INJECT_CONFIG_IRQ queues dev->inject, and vduse_dev_irq_inject() runs the callback under VDUSE's own dev->irq_lock, which vhost does not hold. vduse_dev_reset() does flush_work(&dev->inject), but VHOST_VDPA_SET_CONFIG_CALL never goes through reset, s

osv:CVE-2026-97992

Kernel

Fixed versions: 6.6.160, 6.12.111, 6.18.53, 7.2.7

Complete source record
{
  "id": "bf0f612e4f418eabdb73eef1a15c0a5682cd9bd4db6eefd642ea39e9ef166e46",
  "url": "https://osv.dev/vulnerability/CVE-2026-97992",
  "method": "structured",
  "payload": {
    "kind": "advisory",
    "title": "vhost-vdpa: protect config_ctx from being freed under the config callback",
    "summary": "In the Linux kernel, the following vulnerability has been resolved: vhost-vdpa: protect config_ctx from being freed under the config callback vhost_vdpa_config_cb() loads v->config_ctx and signals it without taking a reference and without holding any lock: struct eventfd_ctx *config_ctx = v->config_ctx; if (config_ctx) eventfd_signal(config_ctx); VHOST_VDPA_SET_CONFIG_CALL replaces that field and drops what is normally the last reference to the old context: swap(ctx, v->config_ctx); if (ctx) eventfd_ctx_put(ctx); eventfd_ctx_put() drops the last kref and frees the context immediately, with no RCU grace period, so a callback that has already loaded the pointer goes on to dereference freed memory. The two sides share no lock: the ioctl runs under vhost_dev.mutex, while the parent invokes the callback from its own interrupt or workqueue context. This is not the reopen refcount underflow fixed by commit f6bbf0010ba0 (\"vhost-vdpa: fix use-after-free of v->config_ctx\"), which was about vhost_vdpa_config_put() leaving a stale pointer behind. Here the pointer is maintained correctly and it is the read side that is unprotected. With VDUSE as the parent this is reachable from userspace with access to /dev/vduse (root by default). VDUSE_DEV_INJECT_CONFIG_IRQ queues dev->inject, and vduse_dev_irq_inject() runs the callback under VDUSE's own dev->irq_lock, which vhost does not hold. vduse_dev_reset() does flush_work(&dev->inject), but VHOST_VDPA_SET_CONFIG_CALL never goes through reset, s",
    "evidence": "osv:CVE-2026-97992",
    "products": [
      {
        "name": {
          "value": "Kernel",
          "evidence": "/affected/1/package/name"
        },
        "prerequisites": [],
        "fixed_versions": [
          {
            "value": "6.6.160",
            "evidence": "/affected/1/ranges"
          },
          {
            "value": "6.12.111",
            "evidence": "/affected/1/ranges"
          },
          {
            "value": "6.18.53",
            "evidence": "/affected/1/ranges"
          },
          {
            "value": "7.2.7",
            "evidence": "/affected/1/ranges"
          }
        ],
        "affected_versions": []
      }
    ],
    "severity": "unknown",
    "structured": {
      "id": "CVE-2026-97992",
      "aliases": [
        "CVE-2026-97992"
      ],
      "affected": [
        {
          "ranges": [
            {
              "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
              "type": "GIT",
              "events": [
                {
                  "introduced": "776f395004d829bbbf18c159ed9beb517a208c71"
                },
                {
                  "fixed": "914c7cc2e3d10dddd3c5529cbe56557c9e01702a"
                },
                {
                  "fixed": "bf35c8948ab7a3eaf1f724fa1e870e3f73a1749b"
                },
                {
                  "fixed": "5a075ee2398929d5cc1393666f219c35332becb1"
                },
                {
                  "fixed": "f4a93f15ed1c8406ba5c8e5b28cafacb2b3bcd11"
                },
                {
                  "fixed": "62be4e3e5f5f947fbf765b914cebdc478f715d12"
                }
              ]
            }
          ],
          "database_specific": {
            "source": "https://storage.googleapis.com/cve-osv-conversion/osv-output/CVE-2026-97992.json"
          }
        },
        {
          "ranges": [
            {
              "type": "ECOSYSTEM",
              "events": [
                {
                  "introduced": "5.8.0"
                },
                {
                  "fixed": "6.6.160"
                }
              ]
            },
            {
              "type": "ECOSYSTEM",
              "events": [
                {
                  "introduced": "6.7.0"
                },
                {
                  "fixed": "6.12.111"
                }
              ]
            },
            {
              "type": "ECOSYSTEM",
              "events": [
                {
                  "introduced": "6.13.0"
                },
                {
                  "fixed": "6.18.53"
                }
              ]
            },
            {
              "type": "ECOSYSTEM",
              "events": [
                {
                  "introduced": "6.19.0"
                },
                {
                  "fixed": "7.2.7"
                }
              ]
            }
          ],
          "package": {
            "name": "Kernel",
            "ecosystem": "Linux"
          },
          "database_specific": {
            "source": "https://storage.googleapis.com/cve-osv-conversion/osv-output/CVE-2026-97992.json"
          }
        }
      ],
      "modified": "2026-10-28T02:30:23.793262310Z",
      "provider": "osv",
      "references": [
        "https://git.kernel.org/stable/c/5a075ee2398929d5cc1393666f219c35332becb1",
        "https://git.kernel.org/stable/c/62be4e3e5f5f947fbf765b914cebdc478f715d12",
        "https://git.kernel.org/stable/c/914c7cc2e3d10dddd3c5529cbe56557c9e01702a",
        "https://git.kernel.org/stable/c/bf35c8948ab7a3eaf1f724fa1e870e3f73a1749b",
        "https://git.kernel.org/stable/c/f4a93f15ed1c8406ba5c8e5b28cafacb2b3bcd11",
        "https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/97xxx/CVE-2026-97992.json",
        "https://nvd.nist.gov/vuln/detail/CVE-2026-97992",
        "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"
      ],
      "provider_metadata": {
        "cna_assigner": "Linux",
        "osv_generated_from": "https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/97xxx/CVE-2026-97992.json"
      }
    },
    "related_cves": [
      {
        "value": "CVE-2026-97992",
        "evidence": "/id"
      }
    ],
    "security_relevant": true,
    "severity_evidence": null
  },
  "source_id": "core-osv",
  "document_id": 490294,
  "published_at": "2026-09-25T10:23:24.472+00:00"
}