CVE-2026-89960: s390/vfio-ap: fix stale pqap_hook pointer on error in vfio_ap_mdev_set_kvm()

Published Sep 16, 2026
·
Updated

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

s390/vfio-ap: fix stale pqaphook pointer on error in vfioapmdevsetkvm()

In vfioapmdevsetkvm(), kvm->arch.crypto.pqaphook is set to &matrixmdev->pqaphook 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.pqaphook pointing at the failing matrixmdev instead of the mdev that legitimately owns the KVM.

Since matrixmdev->kvm is never set on this error path, vfioapmdevunsetkvm() will not clean up the hook when matrixmdev is later closed. If matrixmdev is subsequently freed, any PQAP instruction executed by the guest will dereference the stale pointer through pqaphookrwsem, resulting in a use-after-free.

Since kvm->arch.crypto.pqaphook is only set in the vfioapmdevsetkvm() function and is cleared in the vfioapmdevunsetkvm() function, a check for 'kvm->arch.crypto.pqaphook != NULL' is all that is needed to determine whether it belongs to another mdev. This will alleviate the need to iterate the matrixdev->mdevlist list to see if the kvm object is assigned to another mdev.This was introduced in v3 to alleviate the need to take the mdevslock while iterating the list; however, this did not prevent a potential race condition.

The pqaphookrwsem(write) is now performed inside getupdatelocksforkvm(), which is updated to acquire pqaphookrwsem(write) between kvm->lock and mdevslock. This ordering is consistent with the PQAP intercept path, which acquires pqaphookrwsem in read mode while srcu is held under vcpu->mutex, establishing the dependency: kvm->lock -> vcpu->mutex -> srcu -> pqaphookrwsem(read).

The pqaphookrwsem is now released inside the releaseupdatelocksforkvm(), which is updated to release pqaphookrwsem(write) between mdevslock and kvm->lock.

Additionally, kvmputkvm() in vfioapmdevunsetkvm() is moved after releaseupdatelocksforkvm(). Previously it was called while kvm->lock was held; if it were ever the last reference, kvmdestroyvm() would run under kvm->lock, which would deadlock.

Affected Software

1 affected component
Linux Kernel

Event History

Sep 16, 2026
CVE Published
via MITRE·10:32 AM
Data Sourced
via MITRE·10:32 AM
Description

Frequently Asked Questions

1

Which systems are exposed to this issue?

Systems using the Linux kernel s390 vfio-ap mediated-device support with a KVM instance are exposed when more than one mediated device is assigned or attached to the same KVM instance in the relevant error scenario. The issue involves the s390 PQAP hook used for guest PQAP instructions.

2

What sequence is required to trigger the use-after-free?

A vfio-ap mediated device must attempt to attach to a KVM instance that already has another mediated device attached. The failed device can leave the KVM PQAP hook pointing to it; if that device is later closed and freed, a guest PQAP instruction can dereference the stale pointer.

3

How can administrators tell whether the conflicting assignment condition exists?

The relevant condition is that kvm->arch.crypto.pqap_hook is non-NULL, which indicates that the KVM instance already has a PQAP hook belonging to another mediated device. The fix uses this check rather than iterating the mediated-device list.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203