CVE-2026-89960 (GCVE-0-2026-89960)

Vulnerability from cvelistv5 – Published: 2026-09-16 10:32 – Updated: 2026-09-16 14:40
VLAI
Title
s390/vfio-ap: fix stale pqap_hook pointer on error in vfio_ap_mdev_set_kvm()
Summary
In the Linux kernel, the following vulnerability has been resolved: s390/vfio-ap: fix stale pqap_hook pointer on error in vfio_ap_mdev_set_kvm() In vfio_ap_mdev_set_kvm(), kvm->arch.crypto.pqap_hook is set to &matrix_mdev->pqap_hook before the update locks are acquired and the mdev list is checked for a conflicting assignment. If another mdev is already attached to the same KVM instance, the function returns -EPERM without restoring the hook pointer, leaving kvm->arch.crypto.pqap_hook pointing at the failing matrix_mdev instead of the mdev that legitimately owns the KVM. Since matrix_mdev->kvm is never set on this error path, vfio_ap_mdev_unset_kvm() will not clean up the hook when matrix_mdev is later closed. If matrix_mdev is subsequently freed, any PQAP instruction executed by the guest will dereference the stale pointer through pqap_hook_rwsem, resulting in a use-after-free. Since kvm->arch.crypto.pqap_hook is only set in the vfio_ap_mdev_set_kvm() function and is cleared in the vfio_ap_mdev_unset_kvm() function, a check for 'kvm->arch.crypto.pqap_hook != NULL' is all that is needed to determine whether it belongs to another mdev. This will alleviate the need to iterate the matrix_dev->mdev_list list to see if the kvm object is assigned to another mdev.This was introduced in v3 to alleviate the need to take the mdevs_lock while iterating the list; however, this did not prevent a potential race condition. The pqap_hook_rwsem(write) is now performed inside get_update_locks_for_kvm(), which is updated to acquire pqap_hook_rwsem(write) between kvm->lock and mdevs_lock. This ordering is consistent with the PQAP intercept path, which acquires pqap_hook_rwsem in read mode while srcu is held under vcpu->mutex, establishing the dependency: kvm->lock -> vcpu->mutex -> srcu -> pqap_hook_rwsem(read). The pqap_hook_rwsem is now released inside the release_update_locks_for_kvm(), which is updated to release pqap_hook_rwsem(write) between mdevs_lock and kvm->lock. Additionally, kvm_put_kvm() in vfio_ap_mdev_unset_kvm() is moved after release_update_locks_for_kvm(). Previously it was called while kvm->lock was held; if it were ever the last reference, kvm_destroy_vm() would run under kvm->lock, which would deadlock.
Impacted products
Vendor Product Version CPE status
Linux Linux Affected: 86956e70761b3292156d668e87126844334dd71b , < eb6cc898501a004c0fa8aab951351d9c959b91cc (git)
Affected: 86956e70761b3292156d668e87126844334dd71b , < 6a180adafc2a8a5fbe815985c71b2201e93ab5e1 (git)
Affected: 86956e70761b3292156d668e87126844334dd71b , < fc069d00a0dbef40042fd681554d48dcd5a1d524 (git)
Affected: 86956e70761b3292156d668e87126844334dd71b , < 13bfc94eef389bd664ffc67b00184919902c938a (git)
Affected: 86956e70761b3292156d668e87126844334dd71b , < 4400270ec0348d05dc0439d8f0130853ce7f9e20 (git)
guessed Create a notification for this product.
Linux Linux Affected: 5.15
Unaffected: 0 , < 5.15 (semver)
Unaffected: 6.6.157 , ≤ 6.6.* (semver)
Unaffected: 6.12.110 , ≤ 6.12.* (semver)
Unaffected: 6.18.51 , ≤ 6.18.* (semver)
Unaffected: 7.2.5 , ≤ 7.2.* (semver)
Unaffected: 7.3-rc1 , ≤ * (original_commit_for_fix)
guessed Create a notification for this product.
Show details on NVD website

{
  "containers": {
    "cna": {
      "affected": [
        {
          "defaultStatus": "unaffected",
          "product": "Linux",
          "programFiles": [
            "drivers/s390/crypto/vfio_ap_ops.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "lessThan": "eb6cc898501a004c0fa8aab951351d9c959b91cc",
              "status": "affected",
              "version": "86956e70761b3292156d668e87126844334dd71b",
              "versionType": "git"
            },
            {
              "lessThan": "6a180adafc2a8a5fbe815985c71b2201e93ab5e1",
              "status": "affected",
              "version": "86956e70761b3292156d668e87126844334dd71b",
              "versionType": "git"
            },
            {
              "lessThan": "fc069d00a0dbef40042fd681554d48dcd5a1d524",
              "status": "affected",
              "version": "86956e70761b3292156d668e87126844334dd71b",
              "versionType": "git"
            },
            {
              "lessThan": "13bfc94eef389bd664ffc67b00184919902c938a",
              "status": "affected",
              "version": "86956e70761b3292156d668e87126844334dd71b",
              "versionType": "git"
            },
            {
              "lessThan": "4400270ec0348d05dc0439d8f0130853ce7f9e20",
              "status": "affected",
              "version": "86956e70761b3292156d668e87126844334dd71b",
              "versionType": "git"
            }
          ]
        },
        {
          "defaultStatus": "affected",
          "product": "Linux",
          "programFiles": [
            "drivers/s390/crypto/vfio_ap_ops.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "5.15"
            },
            {
              "lessThan": "5.15",
              "status": "unaffected",
              "version": "0",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.6.*",
              "status": "unaffected",
              "version": "6.6.157",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.12.*",
              "status": "unaffected",
              "version": "6.12.110",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.18.*",
              "status": "unaffected",
              "version": "6.18.51",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "7.2.*",
              "status": "unaffected",
              "version": "7.2.5",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "*",
              "status": "unaffected",
              "version": "7.3-rc1",
              "versionType": "original_commit_for_fix"
            }
          ]
        }
      ],
      "cpeApplicability": [
        {
          "nodes": [
            {
              "cpeMatch": [
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.6.157",
                  "versionStartIncluding": "5.15",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.12.110",
                  "versionStartIncluding": "5.15",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.18.51",
                  "versionStartIncluding": "5.15",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.2.5",
                  "versionStartIncluding": "5.15",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.3-rc1",
                  "versionStartIncluding": "5.15",
                  "vulnerable": true
                }
              ],
              "negate": false,
              "operator": "OR"
            }
          ]
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "In the Linux kernel, the following vulnerability has been resolved:\n\ns390/vfio-ap: fix stale pqap_hook pointer on error in vfio_ap_mdev_set_kvm()\n\nIn vfio_ap_mdev_set_kvm(), kvm-\u003earch.crypto.pqap_hook is set to\n\u0026matrix_mdev-\u003epqap_hook before the update locks are acquired and the\nmdev list is checked for a conflicting assignment. If another mdev is\nalready attached to the same KVM instance, the function returns -EPERM\nwithout restoring the hook pointer, leaving kvm-\u003earch.crypto.pqap_hook\npointing at the failing matrix_mdev instead of the mdev that legitimately\nowns the KVM.\n\nSince matrix_mdev-\u003ekvm is never set on this error path,\nvfio_ap_mdev_unset_kvm() will not clean up the hook when matrix_mdev\nis later closed. If matrix_mdev is subsequently freed, any PQAP\ninstruction executed by the guest will dereference the stale pointer\nthrough pqap_hook_rwsem, resulting in a use-after-free.\n\nSince kvm-\u003earch.crypto.pqap_hook is only set in the vfio_ap_mdev_set_kvm()\nfunction and is cleared in the vfio_ap_mdev_unset_kvm() function, a check\nfor \u0027kvm-\u003earch.crypto.pqap_hook != NULL\u0027 is all that is needed to determine\nwhether it belongs to another mdev. This will alleviate the need to iterate\nthe matrix_dev-\u003emdev_list list to see if the kvm object is assigned to\nanother mdev.This was introduced in v3 to alleviate the need to take the\nmdevs_lock while iterating the list; however, this did not prevent a\npotential race condition.\n\nThe pqap_hook_rwsem(write) is now performed inside\nget_update_locks_for_kvm(), which is updated to acquire\npqap_hook_rwsem(write) between kvm-\u003elock and mdevs_lock. This ordering\nis consistent with the PQAP intercept path, which acquires pqap_hook_rwsem\nin read mode while srcu is held under vcpu-\u003emutex, establishing the\ndependency: kvm-\u003elock -\u003e vcpu-\u003emutex -\u003e srcu -\u003e pqap_hook_rwsem(read).\n\nThe pqap_hook_rwsem is now released inside the\nrelease_update_locks_for_kvm(), which is updated to release\npqap_hook_rwsem(write) between mdevs_lock and kvm-\u003elock.\n\nAdditionally, kvm_put_kvm() in vfio_ap_mdev_unset_kvm() is moved\nafter release_update_locks_for_kvm(). Previously it was called while\nkvm-\u003elock was held; if it were ever the last reference, kvm_destroy_vm()\nwould run under kvm-\u003elock, which would deadlock."
        }
      ],
      "metrics": [
        {
          "cvssV3_1": {
            "baseScore": 8.8,
            "baseSeverity": "HIGH",
            "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
            "version": "3.1"
          },
          "scenarios": [
            {
              "lang": "en",
              "value": "AV:L - The bug is reached by opening vfio-ap mdev fds and linking them to a KVM instance (KVM_DEV_VFIO_FILE_ADD/BIND_IOMMUFD) so vfio_ap_mdev_open_device() calls vfio_ap_mdev_set_kvm(), then by a guest PQAP(AQIC) intercept in handle_pqap(); that is a local VFIO/KVM path with no network or USB exposure.\nAC:L - An attacker who can open two vfio-ap mdevs against the same KVM deterministically hits the -EPERM conflict path that overwrites kvm-\u003earch.crypto.pqap_hook without restoring it, then frees the failing mdev and issues PQAP from the still-running guest; the attacker controls every step, with no victim race or uncontrolled layout.\nPR:L - vfio_ap_mdev_set_kvm() and the PQAP intercept have no capable() gate; /dev/kvm and /dev/vfio nodes are routinely granted to an unprivileged qemu/kvm-group tenant with assigned vfio-ap mdevs, so host root is not required, and user namespaces cannot substitute for this path.\nUI:N - The attacker performs the conflicting VFIO attach, tears down the failing mdev, and executes PQAP in their own guest; prior administrator creation of vfio-ap mdevs is deployment configuration, not victim interaction during exploitation.\nS:C - A guest PQAP intercept on the host calls through kvm-\u003earch.crypto.pqap_hook into a freed ap_matrix_mdev in the host vfio-ap driver, hijacking a host kernel function pointer and crossing the KVM/VFIO guest-to-host isolation boundary (VM escape).\nC:H - After the failing mdev is kvfree\u0027d, handle_pqap() does pqap_hook = *vcpu-\u003ekvm-\u003earch.crypto.pqap_hook, reading a function pointer from the freed ap_matrix_mdev; reclaiming that object yields an arbitrary kernel-read primitive, which kernel UAF guidance scores High.\nI:H - The intercept then invokes that recovered pointer as pqap_hook(vcpu); spraying the freed ap_matrix_mdev replaces the hook with an attacker-controlled address, enabling host kernel control-flow hijack and arbitrary write.\nA:H - The same stale-pointer dereference and call on the freed object causes a host kernel oops or panic when the guest issues PQAP, even if the function pointer is not fully hijacked."
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-09-16T14:40:40.451Z",
        "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "shortName": "Linux"
      },
      "references": [
        {
          "url": "https://git.kernel.org/stable/c/eb6cc898501a004c0fa8aab951351d9c959b91cc"
        },
        {
          "url": "https://git.kernel.org/stable/c/6a180adafc2a8a5fbe815985c71b2201e93ab5e1"
        },
        {
          "url": "https://git.kernel.org/stable/c/fc069d00a0dbef40042fd681554d48dcd5a1d524"
        },
        {
          "url": "https://git.kernel.org/stable/c/13bfc94eef389bd664ffc67b00184919902c938a"
        },
        {
          "url": "https://git.kernel.org/stable/c/4400270ec0348d05dc0439d8f0130853ce7f9e20"
        }
      ],
      "title": "s390/vfio-ap: fix stale pqap_hook pointer on error in vfio_ap_mdev_set_kvm()",
      "x_generator": {
        "engine": "bippy-1.2.0"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
    "assignerShortName": "Linux",
    "cveId": "CVE-2026-89960",
    "datePublished": "2026-09-16T10:32:42.618Z",
    "dateReserved": "2026-09-11T19:38:34.778Z",
    "dateUpdated": "2026-09-16T14:40:40.451Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2",
  "vulnerability-lookup:meta": {
    "epss": {
      "cve": "CVE-2026-89960",
      "date": "2026-09-25",
      "epss": "0.0017",
      "percentile": "0.05626"
    },
    "microsoft_vex": {
      "current_release_date": "2026-09-24T01:30:49.000Z",
      "cve": "CVE-2026-89960",
      "id": "msrc_CVE-2026-89960",
      "initial_release_date": "2026-09-17T01:07:34.000Z",
      "product_status:fixed": "1",
      "product_status:known_affected": "2",
      "source": "Microsoft CSAF VEX",
      "status": "final",
      "title": "s390/vfio-ap: fix stale pqap_hook pointer on error in vfio_ap_mdev_set_kvm()",
      "url": "https://msrc.microsoft.com/csaf/vex/2026/msrc_cve-2026-89960.json",
      "version": "4"
    },
    "nvd": {
      "cve": {
        "affected": [
          {
            "affectedData": [
              {
                "defaultStatus": "unaffected",
                "product": "Linux",
                "programFiles": [
                  "drivers/s390/crypto/vfio_ap_ops.c"
                ],
                "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                "vendor": "Linux",
                "versions": [
                  {
                    "lessThan": "eb6cc898501a004c0fa8aab951351d9c959b91cc",
                    "status": "affected",
                    "version": "86956e70761b3292156d668e87126844334dd71b",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "6a180adafc2a8a5fbe815985c71b2201e93ab5e1",
                    "status": "affected",
                    "version": "86956e70761b3292156d668e87126844334dd71b",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "fc069d00a0dbef40042fd681554d48dcd5a1d524",
                    "status": "affected",
                    "version": "86956e70761b3292156d668e87126844334dd71b",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "13bfc94eef389bd664ffc67b00184919902c938a",
                    "status": "affected",
                    "version": "86956e70761b3292156d668e87126844334dd71b",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "4400270ec0348d05dc0439d8f0130853ce7f9e20",
                    "status": "affected",
                    "version": "86956e70761b3292156d668e87126844334dd71b",
                    "versionType": "git"
                  }
                ]
              },
              {
                "defaultStatus": "affected",
                "product": "Linux",
                "programFiles": [
                  "drivers/s390/crypto/vfio_ap_ops.c"
                ],
                "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                "vendor": "Linux",
                "versions": [
                  {
                    "status": "affected",
                    "version": "5.15"
                  },
                  {
                    "lessThan": "5.15",
                    "status": "unaffected",
                    "version": "0",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "6.6.*",
                    "status": "unaffected",
                    "version": "6.6.157",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "6.12.*",
                    "status": "unaffected",
                    "version": "6.12.110",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "6.18.*",
                    "status": "unaffected",
                    "version": "6.18.51",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "7.2.*",
                    "status": "unaffected",
                    "version": "7.2.5",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "*",
                    "status": "unaffected",
                    "version": "7.3-rc1",
                    "versionType": "original_commit_for_fix"
                  }
                ]
              }
            ],
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
          }
        ],
        "cveTags": [],
        "descriptions": [
          {
            "lang": "en",
            "value": "In the Linux kernel, the following vulnerability has been resolved:\n\ns390/vfio-ap: fix stale pqap_hook pointer on error in vfio_ap_mdev_set_kvm()\n\nIn vfio_ap_mdev_set_kvm(), kvm-\u003earch.crypto.pqap_hook is set to\n\u0026matrix_mdev-\u003epqap_hook before the update locks are acquired and the\nmdev list is checked for a conflicting assignment. If another mdev is\nalready attached to the same KVM instance, the function returns -EPERM\nwithout restoring the hook pointer, leaving kvm-\u003earch.crypto.pqap_hook\npointing at the failing matrix_mdev instead of the mdev that legitimately\nowns the KVM.\n\nSince matrix_mdev-\u003ekvm is never set on this error path,\nvfio_ap_mdev_unset_kvm() will not clean up the hook when matrix_mdev\nis later closed. If matrix_mdev is subsequently freed, any PQAP\ninstruction executed by the guest will dereference the stale pointer\nthrough pqap_hook_rwsem, resulting in a use-after-free.\n\nSince kvm-\u003earch.crypto.pqap_hook is only set in the vfio_ap_mdev_set_kvm()\nfunction and is cleared in the vfio_ap_mdev_unset_kvm() function, a check\nfor \u0027kvm-\u003earch.crypto.pqap_hook != NULL\u0027 is all that is needed to determine\nwhether it belongs to another mdev. This will alleviate the need to iterate\nthe matrix_dev-\u003emdev_list list to see if the kvm object is assigned to\nanother mdev.This was introduced in v3 to alleviate the need to take the\nmdevs_lock while iterating the list; however, this did not prevent a\npotential race condition.\n\nThe pqap_hook_rwsem(write) is now performed inside\nget_update_locks_for_kvm(), which is updated to acquire\npqap_hook_rwsem(write) between kvm-\u003elock and mdevs_lock. This ordering\nis consistent with the PQAP intercept path, which acquires pqap_hook_rwsem\nin read mode while srcu is held under vcpu-\u003emutex, establishing the\ndependency: kvm-\u003elock -\u003e vcpu-\u003emutex -\u003e srcu -\u003e pqap_hook_rwsem(read).\n\nThe pqap_hook_rwsem is now released inside the\nrelease_update_locks_for_kvm(), which is updated to release\npqap_hook_rwsem(write) between mdevs_lock and kvm-\u003elock.\n\nAdditionally, kvm_put_kvm() in vfio_ap_mdev_unset_kvm() is moved\nafter release_update_locks_for_kvm(). Previously it was called while\nkvm-\u003elock was held; if it were ever the last reference, kvm_destroy_vm()\nwould run under kvm-\u003elock, which would deadlock."
          }
        ],
        "id": "CVE-2026-89960",
        "lastModified": "2026-09-16T15:18:20.560",
        "metrics": {
          "cvssMetricV31": [
            {
              "cvssData": {
                "attackComplexity": "LOW",
                "attackVector": "LOCAL",
                "availabilityImpact": "HIGH",
                "baseScore": 8.8,
                "baseSeverity": "HIGH",
                "confidentialityImpact": "HIGH",
                "integrityImpact": "HIGH",
                "privilegesRequired": "LOW",
                "scope": "CHANGED",
                "userInteraction": "NONE",
                "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
                "version": "3.1"
              },
              "exploitabilityScore": 2.0,
              "impactScore": 6.0,
              "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
              "type": "Secondary"
            }
          ]
        },
        "published": "2026-09-16T11:17:06.437",
        "references": [
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/13bfc94eef389bd664ffc67b00184919902c938a"
          },
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/4400270ec0348d05dc0439d8f0130853ce7f9e20"
          },
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/6a180adafc2a8a5fbe815985c71b2201e93ab5e1"
          },
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/eb6cc898501a004c0fa8aab951351d9c959b91cc"
          },
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/fc069d00a0dbef40042fd681554d48dcd5a1d524"
          }
        ],
        "sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "vulnStatus": "Received"
      }
    }
  }
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

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.

Loading…

Loading…

Loading…

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.


Loading…