* [GIT PULL 0/7] KVM: s390: Fixes for 7.2
@ 2026-07-27 9:57 Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 1/7] KVM: s390: pci: Reject adapter interrupt forwarding if already enabled Christian Borntraeger
` (7 more replies)
0 siblings, 8 replies; 14+ messages in thread
From: Christian Borntraeger @ 2026-07-27 9:57 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Janosch Frank, Claudio Imbrenda, David Hildenbrand,
linux-s390, Christian Borntraeger, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Sven Schnelle, Matthew Rosato, Jaehoon Kim,
Douglas Freimuth, Farhan Ali
Paolo,
some more fixes triggered by AI bug reports or testing.
Mostly for PCI support.
This also has a regression fix that we introduced in 7.2-rc1
The following changes since commit 3e3aa6da87d30a0064a17b836685cd43c90a3572:
KVM: s390: pci: Fix handling of AIF enable without AISB (2026-07-09 16:23:10 +0200)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git tags/kvm-s390-master-7.2-2
for you to fetch changes up to 9972befc3e34ff8b6847198c84f11bfc312dde40:
KVM: s390: Fall back to short-term pinning in MAP ioctl (2026-07-27 09:23:53 +0200)
All fixes had no new sashiko findings, just pre-existing issues or
finding that are being fixed by other patches of the series.
We have some more fixes pending for gmap and vfio-ccw that still need
testing or sashiko fixups, but we should process these fixes now.
----------------------------------------------------------------
KVM: s390: Fixes for 7.2
- several fixes for PCI passthru in s390 kvm
- fix a 7.2-rc regression in the adapter interrupt mapping code
----------------------------------------------------------------
Farhan Ali (6):
KVM: s390: pci: Reject adapter interrupt forwarding if already enabled
KVM: s390: pci: Fix memory accounting for pinned/unpinned pages
KVM: s390: pci: Fix missing error codes and memory unaccounting
KVM: s390: pci: Fix NULL dereference on AIBV allocation failure
KVM: s390: pci: Fix resource leak on IRQ registration failure
KVM: s390: pci: Validate AIBV and AISB before pinning guest pages
Jaehoon Kim (1):
KVM: s390: Fall back to short-term pinning in MAP ioctl
Documentation/virt/kvm/devices/s390_flic.rst | 15 +++-
arch/s390/include/asm/kvm_host.h | 5 ++
arch/s390/kvm/interrupt.c | 56 ++++++++++----
arch/s390/kvm/pci.c | 107 +++++++++++++++++++++------
arch/s390/kvm/pci.h | 2 +
5 files changed, 148 insertions(+), 37 deletions(-)
^ permalink raw reply [flat|nested] 14+ messages in thread
* [GIT PULL 1/7] KVM: s390: pci: Reject adapter interrupt forwarding if already enabled
2026-07-27 9:57 [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
@ 2026-07-27 9:57 ` Christian Borntraeger
2026-07-27 10:13 ` sashiko-bot
2026-07-27 9:57 ` [GIT PULL 2/7] KVM: s390: pci: Fix memory accounting for pinned/unpinned pages Christian Borntraeger
` (6 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Christian Borntraeger @ 2026-07-27 9:57 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Janosch Frank, Claudio Imbrenda, David Hildenbrand,
linux-s390, Christian Borntraeger, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Sven Schnelle, Matthew Rosato, Jaehoon Kim,
Douglas Freimuth, Farhan Ali
From: Farhan Ali <alifm@linux.ibm.com>
The MPCIFC instruction doesn't allow registering adapter interrupts without
first unregistering. So reject any request to enable interrupt forwarding
if its already enabled for the zPCI device. This also fixes overwriting and
thus leaking resources when the ioctl is called multiple times for the same
device.
Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
Cc: stable@vger.kernel.org
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
arch/s390/kvm/pci.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index 720bb58cabe2..d2a11cdf6941 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -237,6 +237,10 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
if (zdev->gisa == 0)
return -EINVAL;
+ /* AIF already enabled for the device */
+ if (zdev->kzdev->fib.fmt0.aibv != 0)
+ return -EINVAL;
+
kvm = zdev->kzdev->kvm;
msi_vecs = min_t(unsigned int, fib->fmt0.noi, zdev->max_msi);
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [GIT PULL 2/7] KVM: s390: pci: Fix memory accounting for pinned/unpinned pages
2026-07-27 9:57 [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 1/7] KVM: s390: pci: Reject adapter interrupt forwarding if already enabled Christian Borntraeger
@ 2026-07-27 9:57 ` Christian Borntraeger
2026-07-27 10:11 ` sashiko-bot
2026-07-27 9:57 ` [GIT PULL 3/7] KVM: s390: pci: Fix missing error codes and memory unaccounting Christian Borntraeger
` (5 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Christian Borntraeger @ 2026-07-27 9:57 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Janosch Frank, Claudio Imbrenda, David Hildenbrand,
linux-s390, Christian Borntraeger, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Sven Schnelle, Matthew Rosato, Jaehoon Kim,
Douglas Freimuth, Farhan Ali
From: Farhan Ali <alifm@linux.ibm.com>
The account_mem() and unaccount_mem() functions call get_uid() which
increments the reference count of struct user_struct on every invocation.
But we don't decrement the count by calling free_uid(). It also
accounted/unaccounted the pages against the current->mm. But its possible
the unaccount_mem() can be called from a different process context than the
one that originally pinned the pages.
Let's fix this by storing the pinning process user_struct and mm_struct
when accounting for pinned pages, and subsequently free these resources
when the pages are unpinned.
Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
Cc: stable@vger.kernel.org
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
[borntraeger@linux.ibm.com: Fixed whitespace]
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
arch/s390/kvm/pci.c | 43 ++++++++++++++++++++++++++++++++-----------
arch/s390/kvm/pci.h | 2 ++
2 files changed, 34 insertions(+), 11 deletions(-)
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index d2a11cdf6941..0741aed442bc 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -190,33 +190,54 @@ static int kvm_zpci_clear_airq(struct zpci_dev *zdev)
return cc ? -EIO : 0;
}
-static inline void unaccount_mem(unsigned long nr_pages)
+static inline void unaccount_mem(struct kvm_zdev *kzdev, unsigned long nr_pages)
{
- struct user_struct *user = get_uid(current_user());
+ struct user_struct *user = kzdev->user_account;
+ struct mm_struct *mm_account = kzdev->mm_account;
- if (user)
+ if (user) {
atomic_long_sub(nr_pages, &user->locked_vm);
- if (current->mm)
- atomic64_sub(nr_pages, ¤t->mm->pinned_vm);
+ free_uid(user);
+ kzdev->user_account = NULL;
+ }
+
+ if (mm_account) {
+ atomic64_sub(nr_pages, &mm_account->pinned_vm);
+ mmdrop(mm_account);
+ kzdev->mm_account = NULL;
+ }
}
-static inline int account_mem(unsigned long nr_pages)
+static inline int account_mem(struct kvm_zdev *kzdev, unsigned long nr_pages)
{
struct user_struct *user = get_uid(current_user());
unsigned long page_limit, cur_pages, new_pages;
+ int rc = 0;
page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
cur_pages = atomic_long_read(&user->locked_vm);
do {
new_pages = cur_pages + nr_pages;
- if (new_pages > page_limit)
- return -ENOMEM;
+ if (new_pages > page_limit) {
+ rc = -ENOMEM;
+ goto out;
+ }
} while (!atomic_long_try_cmpxchg(&user->locked_vm, &cur_pages, new_pages));
- atomic64_add(nr_pages, ¤t->mm->pinned_vm);
+ if (current->mm) {
+ mmgrab(current->mm);
+ atomic64_add(nr_pages, ¤t->mm->pinned_vm);
+ }
+
+ kzdev->user_account = user;
+ kzdev->mm_account = current->mm;
return 0;
+
+out:
+ free_uid(user);
+ return rc;
}
static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
@@ -279,7 +300,7 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
}
/* Account for pinned pages, roll back on failure */
- if (account_mem(pcount))
+ if (account_mem(zdev->kzdev, pcount))
goto unpin2;
/* AISB must be allocated before we can fill in GAITE */
@@ -400,7 +421,7 @@ static int kvm_s390_pci_aif_disable(struct zpci_dev *zdev, bool force)
pcount++;
}
if (pcount > 0)
- unaccount_mem(pcount);
+ unaccount_mem(kzdev, pcount);
out:
mutex_unlock(&aift->aift_lock);
diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h
index ff0972dd5e71..fdf8c7bf4ed0 100644
--- a/arch/s390/kvm/pci.h
+++ b/arch/s390/kvm/pci.h
@@ -22,6 +22,8 @@ struct kvm_zdev {
struct kvm *kvm;
struct zpci_fib fib;
struct list_head entry;
+ struct user_struct *user_account;
+ struct mm_struct *mm_account;
};
struct zpci_gaite {
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [GIT PULL 3/7] KVM: s390: pci: Fix missing error codes and memory unaccounting
2026-07-27 9:57 [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 1/7] KVM: s390: pci: Reject adapter interrupt forwarding if already enabled Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 2/7] KVM: s390: pci: Fix memory accounting for pinned/unpinned pages Christian Borntraeger
@ 2026-07-27 9:57 ` Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 4/7] KVM: s390: pci: Fix NULL dereference on AIBV allocation failure Christian Borntraeger
` (4 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Christian Borntraeger @ 2026-07-27 9:57 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Janosch Frank, Claudio Imbrenda, David Hildenbrand,
linux-s390, Christian Borntraeger, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Sven Schnelle, Matthew Rosato, Jaehoon Kim,
Douglas Freimuth, Farhan Ali
From: Farhan Ali <alifm@linux.ibm.com>
In kvm_s390_pci_aif_enable() two error paths failed to set an error code,
causing the function to return 0 on failure. It also failed to rollback
memory accounting on failure. Fix both by propagating an error code on
failure and calling unaccount_mem() in the cleanup path.
Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
Cc: stable@vger.kernel.org
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
arch/s390/kvm/pci.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index 0741aed442bc..36eb30953bb5 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -300,14 +300,17 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
}
/* Account for pinned pages, roll back on failure */
- if (account_mem(zdev->kzdev, pcount))
+ rc = account_mem(zdev->kzdev, pcount);
+ if (rc)
goto unpin2;
/* AISB must be allocated before we can fill in GAITE */
mutex_lock(&aift->aift_lock);
bit = airq_iv_alloc_bit(aift->sbv);
- if (bit == -1UL)
+ if (bit == -1UL) {
+ rc = -ENOMEM;
goto unlock;
+ }
zdev->aisb = bit; /* store the summary bit number */
zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA |
AIRQ_IV_BITLOCK |
@@ -351,6 +354,8 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
return rc;
unlock:
+ if (pcount > 0)
+ unaccount_mem(zdev->kzdev, pcount);
mutex_unlock(&aift->aift_lock);
unpin2:
if (fib->fmt0.sum == 1)
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [GIT PULL 4/7] KVM: s390: pci: Fix NULL dereference on AIBV allocation failure
2026-07-27 9:57 [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
` (2 preceding siblings ...)
2026-07-27 9:57 ` [GIT PULL 3/7] KVM: s390: pci: Fix missing error codes and memory unaccounting Christian Borntraeger
@ 2026-07-27 9:57 ` Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 5/7] KVM: s390: pci: Fix resource leak on IRQ registration failure Christian Borntraeger
` (3 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Christian Borntraeger @ 2026-07-27 9:57 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Janosch Frank, Claudio Imbrenda, David Hildenbrand,
linux-s390, Christian Borntraeger, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Sven Schnelle, Matthew Rosato, Jaehoon Kim,
Douglas Freimuth, Farhan Ali
From: Farhan Ali <alifm@linux.ibm.com>
The airq_iv_create() can return NULL on failure, but the return value was
never checked. If it fails, zdev->aibv will be NULL and fail when
dereferenced in kvm_zpci_set_airq(). Add a NULL check and free the
previously allocated AISB bit and zdev->aisb on failure.
Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
Cc: stable@vger.kernel.org
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
arch/s390/kvm/pci.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index 36eb30953bb5..1eb127fc9f89 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -317,6 +317,11 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
AIRQ_IV_GUESTVEC,
phys_to_virt(fib->fmt0.aibv));
+ if (!zdev->aibv) {
+ rc = -ENOMEM;
+ goto free_aisb;
+ }
+
spin_lock_irq(&aift->gait_lock);
gaite = aift->gait + zdev->aisb;
@@ -353,6 +358,9 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
rc = kvm_zpci_set_airq(zdev);
return rc;
+free_aisb:
+ airq_iv_free_bit(aift->sbv, zdev->aisb);
+ zdev->aisb = 0;
unlock:
if (pcount > 0)
unaccount_mem(zdev->kzdev, pcount);
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [GIT PULL 5/7] KVM: s390: pci: Fix resource leak on IRQ registration failure
2026-07-27 9:57 [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
` (3 preceding siblings ...)
2026-07-27 9:57 ` [GIT PULL 4/7] KVM: s390: pci: Fix NULL dereference on AIBV allocation failure Christian Borntraeger
@ 2026-07-27 9:57 ` Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 6/7] KVM: s390: pci: Validate AIBV and AISB before pinning guest pages Christian Borntraeger
` (2 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Christian Borntraeger @ 2026-07-27 9:57 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Janosch Frank, Claudio Imbrenda, David Hildenbrand,
linux-s390, Christian Borntraeger, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Sven Schnelle, Matthew Rosato, Jaehoon Kim,
Douglas Freimuth, Farhan Ali
From: Farhan Ali <alifm@linux.ibm.com>
Currently if kvm_zpci_set_airq() fails, kvm_s390_pci_aif_enable() returns
the error code but doesn't do any resource cleanup thus leaking resources.
Fix this by cleaning up all the resources such as the GAITE, AIBV, AISB and
unpinning any pinned pages. While at it, remove dead code that stored FIB
values that were never referenced.
As part of the cleanup, we are also holding the aift_lock a bit longer, as
we hold the lock while executing the MPCIFC instruction. Though this is not
strictly necessary, it means we don't have to drop and re-acquire in the
error case.
Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
Cc: stable@vger.kernel.org
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
arch/s390/kvm/pci.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index 1eb127fc9f89..50f495bc8303 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -344,19 +344,32 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
aift->kzdev[zdev->aisb] = zdev->kzdev;
spin_unlock_irq(&aift->gait_lock);
- /* Update guest FIB for re-issue */
- fib->fmt0.aisbo = zdev->aisb & 63;
- fib->fmt0.aisb = virt_to_phys(aift->sbv->vector) + (zdev->aisb / 64) * 8;
- fib->fmt0.isc = gisc;
-
/* Save some guest fib values in the host for later use */
- zdev->kzdev->fib.fmt0.isc = fib->fmt0.isc;
+ zdev->kzdev->fib.fmt0.isc = gisc;
zdev->kzdev->fib.fmt0.aibv = fib->fmt0.aibv;
- mutex_unlock(&aift->aift_lock);
/* Issue the clp to setup the irq now */
rc = kvm_zpci_set_airq(zdev);
- return rc;
+ if (!rc) {
+ mutex_unlock(&aift->aift_lock);
+ return rc;
+ }
+
+ /* Start cleanup */
+ zdev->kzdev->fib.fmt0.isc = 0;
+ zdev->kzdev->fib.fmt0.aibv = 0;
+
+ spin_lock_irq(&aift->gait_lock);
+ gaite->count--;
+ gaite->aisb = 0;
+ gaite->gisc = 0;
+ gaite->aisbo = 0;
+ gaite->gisa = 0;
+ aift->kzdev[zdev->aisb] = NULL;
+ spin_unlock_irq(&aift->gait_lock);
+
+ airq_iv_release(zdev->aibv);
+ zdev->aibv = NULL;
free_aisb:
airq_iv_free_bit(aift->sbv, zdev->aisb);
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [GIT PULL 6/7] KVM: s390: pci: Validate AIBV and AISB before pinning guest pages
2026-07-27 9:57 [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
` (4 preceding siblings ...)
2026-07-27 9:57 ` [GIT PULL 5/7] KVM: s390: pci: Fix resource leak on IRQ registration failure Christian Borntraeger
@ 2026-07-27 9:57 ` Christian Borntraeger
2026-07-27 10:18 ` sashiko-bot
2026-07-27 9:57 ` [GIT PULL 7/7] KVM: s390: Fall back to short-term pinning in MAP ioctl Christian Borntraeger
2026-07-27 11:24 ` [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
7 siblings, 1 reply; 14+ messages in thread
From: Christian Borntraeger @ 2026-07-27 9:57 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Janosch Frank, Claudio Imbrenda, David Hildenbrand,
linux-s390, Christian Borntraeger, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Sven Schnelle, Matthew Rosato, Jaehoon Kim,
Douglas Freimuth, Farhan Ali
From: Farhan Ali <alifm@linux.ibm.com>
The AIBV holds one bit per MSI-X vector for a given function. The size of
the bit vector is derived from the NOI and the AIBVO. If the size of the
AIBV exceeds a single page boundary, then reject the request as we cannot
safely pin the guest AIBV.
Similarly reject the request if the AISB address is not 8-byte aligned as
the architecture requires doubleword alignment for the summary bit address.
Since the AISBO can address up to 64 bits, the size of the AISB can only be
8 bytes for the function. This also ensures the AISB doesn't exceed a
single page boundary.
Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
Cc: stable@vger.kernel.org
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
arch/s390/kvm/pci.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index 50f495bc8303..50f5ec79600e 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -244,7 +244,7 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
bool assist)
{
struct page *pages[1], *aibv_page, *aisb_page = NULL;
- unsigned int msi_vecs, idx;
+ unsigned int msi_vecs, idx, size;
struct zpci_gaite *gaite;
unsigned long hva, bit;
struct kvm *kvm;
@@ -271,6 +271,14 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
return gisc;
/* Replace AIBV address */
+ size = BITS_TO_LONGS(msi_vecs + fib->fmt0.aibvo) * sizeof(unsigned long);
+ npages = DIV_ROUND_UP((fib->fmt0.aibv & ~PAGE_MASK) + size, PAGE_SIZE);
+ /* AIBV cannot span more than 1 page */
+ if (npages > 1) {
+ rc = -EINVAL;
+ goto out;
+ }
+
idx = srcu_read_lock(&kvm->srcu);
hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aibv));
npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM, pages);
@@ -286,6 +294,12 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
/* Pin the guest AISB if one was specified */
if (fib->fmt0.sum == 1) {
+ /* AISB must be dword aligned */
+ if (fib->fmt0.aisb & 0x7) {
+ rc = -EINVAL;
+ goto unpin1;
+ }
+
idx = srcu_read_lock(&kvm->srcu);
hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aisb));
npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM,
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [GIT PULL 7/7] KVM: s390: Fall back to short-term pinning in MAP ioctl
2026-07-27 9:57 [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
` (5 preceding siblings ...)
2026-07-27 9:57 ` [GIT PULL 6/7] KVM: s390: pci: Validate AIBV and AISB before pinning guest pages Christian Borntraeger
@ 2026-07-27 9:57 ` Christian Borntraeger
2026-07-27 10:10 ` sashiko-bot
2026-07-27 11:24 ` [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
7 siblings, 1 reply; 14+ messages in thread
From: Christian Borntraeger @ 2026-07-27 9:57 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Janosch Frank, Claudio Imbrenda, David Hildenbrand,
linux-s390, Christian Borntraeger, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Sven Schnelle, Matthew Rosato, Jaehoon Kim,
Douglas Freimuth, Farhan Ali
From: Jaehoon Kim <jhkim@linux.ibm.com>
FOLL_LONGTERM pinning fails for some memory types, such as file-backed
guest memory. As a result, kvm_s390_adapter_map() returns -EINVAL and
irqfd adapter registration fails even though interrupt delivery could
still work via the existing non-atomic path.
When FOLL_LONGTERM pinning fails, verify that the page is accessible
using a short-term pin instead. If the short-term pin succeeds, unpin
the page and add a map entry with pinned=false to preserve MAP/UNMAP
symmetry. The non-atomic irqfd path already performs short-term pinning
for interrupt delivery, so this restores the previous behavior for
memory that cannot be pinned long-term.
get_map_info() is updated to return NULL for unpinned entries so that
the atomic irqfd fast path falls back to the non-atomic path.
kvm_s390_adapter_unmap() and kvm_s390_unmap_all_adapters() skip dirty
marking and unpin for unpinned entries.
Update Documentation/virt/kvm/devices/s390_flic.rst to reflect the
new MAP/UNMAP behavior.
Fixes: c9a568838086 ("KVM: s390: Add map/unmap ioctl and clean mappings post-guest")
Signed-off-by: Jaehoon Kim <jhkim@linux.ibm.com>
Reviewed-by: Douglas Freimuth <freimuth@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
Documentation/virt/kvm/devices/s390_flic.rst | 15 +++++-
arch/s390/include/asm/kvm_host.h | 5 ++
arch/s390/kvm/interrupt.c | 56 +++++++++++++++-----
3 files changed, 60 insertions(+), 16 deletions(-)
diff --git a/Documentation/virt/kvm/devices/s390_flic.rst b/Documentation/virt/kvm/devices/s390_flic.rst
index b784f8016748..983c858b444a 100644
--- a/Documentation/virt/kvm/devices/s390_flic.rst
+++ b/Documentation/virt/kvm/devices/s390_flic.rst
@@ -112,9 +112,20 @@ Groups:
mask or unmask the adapter, as specified in mask
KVM_S390_IO_ADAPTER_MAP
- This is now a no-op. The mapping is purely done by the irq route.
+ Map an adapter indicator or summary page for long-term pinning so that
+ interrupt injection can be performed in atomic context. If long-term
+ pinning is not possible (e.g. file-backed memory), the page is verified
+ via a short-term pin and the ioctl returns success; interrupt injection
+ will use the non-atomic irqfd path with short-term pinning on each
+ interrupt. In Secure Execution mode this is a no-op and the ioctl
+ returns success.
+
KVM_S390_IO_ADAPTER_UNMAP
- This is now a no-op. The mapping is purely done by the irq route.
+ Unmap a previously mapped adapter indicator or summary page and release
+ the long-term pin. If the page was not long-term pinned (e.g. file-backed
+ memory), the map entry is removed and success is returned; if no prior
+ map entry exists, -ENOENT is returned. In Secure Execution mode this is
+ a no-op and the ioctl returns success.
KVM_DEV_FLIC_AISM
modify the adapter-interruption-suppression mode for a given isc if the
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index eaa34c5bd3c1..c172f9b212d1 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -476,6 +476,11 @@ struct s390_map_info {
__u64 guest_addr;
__u64 addr;
struct page *page;
+ /*
+ * True if the page is long-term pinned. False if long-term pinning
+ * failed and this entry exists only to preserve MAP/UNMAP symmetry.
+ */
+ bool pinned;
};
struct s390_io_adapter {
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 9e3e6b0d72ad..7514d9e2403c 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -2520,8 +2520,22 @@ static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
map->addr = host_addr;
map->page = pin_map_page(kvm, host_addr, FOLL_LONGTERM);
if (!map->page) {
- ret = -EINVAL;
- goto out;
+ /*
+ * Long-term pinning may fail for memory types such as file-backed
+ * memory. Verify that short-term pinning succeeds so that the
+ * non-atomic irqfd path can handle interrupt injection.
+ */
+ map->page = pin_map_page(kvm, host_addr, 0);
+ if (!map->page) {
+ ret = -EINVAL;
+ goto out;
+ }
+ unpin_user_page(map->page);
+ map->page = NULL;
+ map->pinned = false;
+ /* Add an entry to preserve MAP/UNMAP symmetry. */
+ } else {
+ map->pinned = true;
}
spin_lock_irqsave(&adapter->maps_lock, flags);
if (adapter->nr_maps < MAX_S390_ADAPTER_MAPS) {
@@ -2532,7 +2546,7 @@ static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
ret = -EINVAL;
}
spin_unlock_irqrestore(&adapter->maps_lock, flags);
- if (ret)
+ if (ret && map->page)
unpin_user_page(map->page);
out:
if (ret)
@@ -2546,6 +2560,7 @@ static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
struct s390_map_info *map, *tmp, *map_to_free;
struct page *map_page_to_put = NULL;
u64 map_addr_to_mark = 0;
+ bool map_pinned = false;
unsigned long flags;
int found = 0, idx;
@@ -2560,6 +2575,7 @@ static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
list_del(&map->list);
map_page_to_put = map->page;
map_addr_to_mark = map->guest_addr;
+ map_pinned = map->pinned;
map_to_free = map;
break;
}
@@ -2568,11 +2584,18 @@ static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
if (found) {
kfree(map_to_free);
- idx = srcu_read_lock(&kvm->srcu);
- mark_page_dirty(kvm, map_addr_to_mark >> PAGE_SHIFT);
- set_page_dirty_lock(map_page_to_put);
- srcu_read_unlock(&kvm->srcu, idx);
- unpin_user_page(map_page_to_put);
+ if (map_pinned) {
+ /*
+ * Only long-term pinned pages need to be marked dirty
+ * and released. Fallback entries exist only for
+ * MAP/UNMAP symmetry.
+ */
+ idx = srcu_read_lock(&kvm->srcu);
+ mark_page_dirty(kvm, map_addr_to_mark >> PAGE_SHIFT);
+ set_page_dirty_lock(map_page_to_put);
+ srcu_read_unlock(&kvm->srcu, idx);
+ unpin_user_page(map_page_to_put);
+ }
}
return found ? 0 : -ENOENT;
@@ -2598,11 +2621,13 @@ void kvm_s390_unmap_all_adapters(struct kvm *kvm)
list_for_each_entry_safe(map, tmp, &local_list, list) {
list_del(&map->list);
- idx = srcu_read_lock(&kvm->srcu);
- mark_page_dirty(kvm, map->guest_addr >> PAGE_SHIFT);
- set_page_dirty_lock(map->page);
- srcu_read_unlock(&kvm->srcu, idx);
- unpin_user_page(map->page);
+ if (map->pinned) {
+ idx = srcu_read_lock(&kvm->srcu);
+ mark_page_dirty(kvm, map->guest_addr >> PAGE_SHIFT);
+ set_page_dirty_lock(map->page);
+ srcu_read_unlock(&kvm->srcu, idx);
+ unpin_user_page(map->page);
+ }
kfree(map);
}
}
@@ -2929,8 +2954,11 @@ static struct s390_map_info *get_map_info(struct s390_io_adapter *adapter,
return NULL;
list_for_each_entry(map, &adapter->maps, list) {
- if (map->addr == addr)
+ if (map->addr == addr) {
+ if (!map->pinned)
+ return NULL;
return map;
+ }
}
return NULL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [GIT PULL 7/7] KVM: s390: Fall back to short-term pinning in MAP ioctl
2026-07-27 9:57 ` [GIT PULL 7/7] KVM: s390: Fall back to short-term pinning in MAP ioctl Christian Borntraeger
@ 2026-07-27 10:10 ` sashiko-bot
0 siblings, 0 replies; 14+ messages in thread
From: sashiko-bot @ 2026-07-27 10:10 UTC (permalink / raw)
To: Christian Borntraeger
Cc: kvm, Vasily Gorbik, Alexander Gordeev, Heiko Carstens, linux-s390
> From: Jaehoon Kim <jhkim@linux.ibm.com>
>
> FOLL_LONGTERM pinning fails for some memory types, such as file-backed
> guest memory. As a result, kvm_s390_adapter_map() returns -EINVAL and
> irqfd adapter registration fails even though interrupt delivery could
> still work via the existing non-atomic path.
>
> When FOLL_LONGTERM pinning fails, verify that the page is accessible
> using a short-term pin instead. If the short-term pin succeeds, unpin
> the page and add a map entry with pinned=false to preserve MAP/UNMAP
> symmetry. The non-atomic irqfd path already performs short-term pinning
> for interrupt delivery, so this restores the previous behavior for
> memory that cannot be pinned long-term.
>
> get_map_info() is updated to return NULL for unpinned entries so that
> the atomic irqfd fast path falls back to the non-atomic path.
> kvm_s390_adapter_unmap() and kvm_s390_unmap_all_adapters() skip dirty
> marking and unpin for unpinned entries.
>
> Update Documentation/virt/kvm/devices/s390_flic.rst to reflect the
> new MAP/UNMAP behavior.
>
> Fixes: c9a568838086 ("KVM: s390: Add map/unmap ioctl and clean mappings post-guest")
> Signed-off-by: Jaehoon Kim <jhkim@linux.ibm.com>
> Reviewed-by: Douglas Freimuth <freimuth@linux.ibm.com>
> Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
> Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260727095720.9150-8-borntraeger@linux.ibm.com?part=1
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [GIT PULL 2/7] KVM: s390: pci: Fix memory accounting for pinned/unpinned pages
2026-07-27 9:57 ` [GIT PULL 2/7] KVM: s390: pci: Fix memory accounting for pinned/unpinned pages Christian Borntraeger
@ 2026-07-27 10:11 ` sashiko-bot
2026-07-27 11:15 ` Christian Borntraeger
0 siblings, 1 reply; 14+ messages in thread
From: sashiko-bot @ 2026-07-27 10:11 UTC (permalink / raw)
To: Christian Borntraeger
Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev, kvm
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] The patch introduces `mm_struct` and `user_struct` reference count leaks on the `airq_iv_alloc_bit()` error path.
- [High] Calling the `KVM_S390_ZPCIOP_REG_AEN` ioctl multiple times sequentially overwrites `kzdev->mm_account` and `kzdev->user_account`, permanently leaking the previously acquired kernel object references.
Pre-existing issues:
- [High] Missing NULL check for `airq_iv_create()` return value causes a guaranteed NULL pointer dereference.
--
--- Patch [1]: [GIT PULL 2/7] KVM: s390: pci: Fix memory accounting for pinned/unpinned pages ---
commit c8a84dcb0557ca0ba1070398f64a0a7a9a08e82b
Author: Farhan Ali <alifm@linux.ibm.com>
Date: Mon Jul 27 09:57:15 2026 +0000
KVM: s390: pci: Fix memory accounting for pinned/unpinned pages
This patch stores the pinning process user_struct and mm_struct when
accounting for pinned pages. It subsequently frees these resources when the
pages are unpinned to resolve context issues.
> diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
> index 5b075c38998e3..c2f5085a0f5f1 100644
> --- a/arch/s390/kvm/pci.c
> +++ b/arch/s390/kvm/pci.c
[ ... ]
> @@ -190,33 +190,54 @@ static int kvm_zpci_clear_airq(struct zpci_dev *zdev)
[ ... ]
> -static inline int account_mem(unsigned long nr_pages)
> +static inline int account_mem(struct kvm_zdev *kzdev, unsigned long nr_pages)
> {
> struct user_struct *user = get_uid(current_user());
> unsigned long page_limit, cur_pages, new_pages;
> + int rc = 0;
>
> page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
>
> cur_pages = atomic_long_read(&user->locked_vm);
> do {
> new_pages = cur_pages + nr_pages;
> - if (new_pages > page_limit)
> - return -ENOMEM;
> + if (new_pages > page_limit) {
> + rc = -ENOMEM;
> + goto out;
> + }
> } while (!atomic_long_try_cmpxchg(&user->locked_vm, &cur_pages, new_pages));
>
> - atomic64_add(nr_pages, ¤t->mm->pinned_vm);
> + if (current->mm) {
> + mmgrab(current->mm);
> + atomic64_add(nr_pages, ¤t->mm->pinned_vm);
> + }
> +
> + kzdev->user_account = user;
> + kzdev->mm_account = current->mm;
[Severity: High]
If the KVM_S390_ZPCIOP_REG_AEN ioctl invokes kvm_s390_pci_aif_enable()
multiple times sequentially, will this unconditionally overwrite
kzdev->user_account and kzdev->mm_account?
It appears that if the device is already enabled, the previously acquired
references would be permanently leaked since unaccount_mem() isn't called
before assigning the new pointers here.
>
> return 0;
> +
> +out:
> + free_uid(user);
> + return rc;
> }
>
> static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
> @@ -275,7 +296,7 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
> }
>
> /* Account for pinned pages, roll back on failure */
> - if (account_mem(pcount))
> + if (account_mem(zdev->kzdev, pcount))
> goto unpin2;
>
> /* AISB must be allocated before we can fill in GAITE */
[Severity: High]
If airq_iv_alloc_bit() fails later in this function, the error path
jumps to the unlock and unpin labels:
kvm_s390_pci_aif_enable() {
...
bit = airq_iv_alloc_bit(aift->sbv);
if (bit == -1UL)
goto unlock;
...
unlock:
mutex_unlock(&aift->aift_lock);
unpin2:
if (fib->fmt0.sum == 1)
unpin_user_page(aisb_page);
...
}
Does this error path need to call unaccount_mem() to prevent leaking the
mm_struct and user_struct references acquired by account_mem() earlier?
[Severity: High]
This is a pre-existing issue, but is it possible for airq_iv_create() to
return NULL under memory pressure?
If it fails, zdev->aibv is assigned NULL a bit later in
kvm_s390_pci_aif_enable():
kvm_s390_pci_aif_enable() {
...
zdev->aibv = airq_iv_create(...);
...
rc = kvm_zpci_set_airq(zdev);
...
}
Could this lead to a NULL pointer dereference when kvm_zpci_set_airq()
attempts to access airq_iv_end(zdev->aibv)?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260727095720.9150-3-borntraeger@linux.ibm.com?part=1
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [GIT PULL 1/7] KVM: s390: pci: Reject adapter interrupt forwarding if already enabled
2026-07-27 9:57 ` [GIT PULL 1/7] KVM: s390: pci: Reject adapter interrupt forwarding if already enabled Christian Borntraeger
@ 2026-07-27 10:13 ` sashiko-bot
0 siblings, 0 replies; 14+ messages in thread
From: sashiko-bot @ 2026-07-27 10:13 UTC (permalink / raw)
To: Christian Borntraeger
Cc: Alexander Gordeev, linux-s390, kvm, Heiko Carstens, Vasily Gorbik
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] kvm_s390_pci_aif_enable() silently returns success (0) when account_mem() or airq_iv_alloc_bit() fail, leaving the device non-functional in the guest.
- [High] Missing NULL check for airq_iv_create() return value causes a guaranteed kernel panic on allocation failure.
- [High] The helper functions account_mem() and unaccount_mem() permanently leak user_struct reference counts and inaccurately uncharge teardown threads.
--
--- Patch [1]: [GIT PULL 1/7] KVM: s390: pci: Reject adapter interrupt forwarding if already enabled ---
commit 834c3470cb709cfa95cf6f7b8315fe450f54610b
Author: Farhan Ali <alifm@linux.ibm.com>
KVM: s390: pci: Reject adapter interrupt forwarding if already enabled
The MPCIFC instruction doesn't allow registering adapter interrupts without
first unregistering. So reject any request to enable interrupt forwarding
if its already enabled for the zPCI device. This also fixes overwriting and
thus leaking resources when the ioctl is called multiple times for the same
device.
Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
Cc: stable@vger.kernel.org
> diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
> index 5b075c38998e3..02ec50a01fed2 100644
> --- a/arch/s390/kvm/pci.c
> +++ b/arch/s390/kvm/pci.c
> @@ -237,6 +237,10 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
> if (zdev->gisa == 0)
> return -EINVAL;
>
> + /* AIF already enabled for the device */
> + if (zdev->kzdev->fib.fmt0.aibv != 0)
> + return -EINVAL;
> +
> kvm = zdev->kzdev->kvm;
> msi_vecs = min_t(unsigned int, fib->fmt0.noi, zdev->max_msi);
>
[Severity: High]
This is a pre-existing issue, but does kvm_s390_pci_aif_enable() silently
return success when account_mem() fails?
If account_mem() fails, it jumps to unpin2, but rc remains 0:
arch/s390/kvm/pci.c:kvm_s390_pci_aif_enable() {
...
/* Account for pinned pages, roll back on failure */
if (account_mem(pcount))
goto unpin2;
...
unpin2:
if (fib->fmt0.sum == 1)
unpin_user_page(aisb_page);
unpin1:
unpin_user_page(aibv_page);
out:
return rc;
}
The same happens if airq_iv_alloc_bit() fails:
arch/s390/kvm/pci.c:kvm_s390_pci_aif_enable() {
...
bit = airq_iv_alloc_bit(aift->sbv);
if (bit == -1UL)
goto unlock;
...
}
Should rc be updated to a negative error code before jumping to these cleanup
labels?
[Severity: High]
This is a pre-existing issue, but could airq_iv_create() return NULL and cause
a panic?
arch/s390/kvm/pci.c:kvm_s390_pci_aif_enable() {
...
zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA |
AIRQ_IV_BITLOCK |
AIRQ_IV_GUESTVEC,
phys_to_virt(fib->fmt0.aibv));
spin_lock_irq(&aift->gait_lock);
...
}
If airq_iv_create() fails and returns NULL, zdev->aibv becomes NULL. Later,
when kvm_zpci_set_airq() is called, it might dereference this NULL pointer:
arch/s390/kvm/pci.c:kvm_zpci_set_airq() {
...
fib.fmt0.noi = airq_iv_end(zdev->aibv);
...
}
Should we check the return value of airq_iv_create() and handle the failure?
[Severity: High]
This isn't a bug introduced by this patch, but do the accounting functions leak
user_struct references?
In account_mem():
arch/s390/kvm/pci.c:account_mem() {
...
struct user_struct *user = get_uid(current_user());
...
}
And in unaccount_mem():
arch/s390/kvm/pci.c:unaccount_mem() {
...
struct user_struct *user = get_uid(current_user());
if (user)
atomic_long_sub(nr_pages, &user->locked_vm);
if (current->mm)
atomic64_sub(nr_pages, ¤t->mm->pinned_vm);
...
}
Both functions call get_uid(current_user()) which increments the user's
reference count, but they do not seem to call free_uid().
Additionally, unaccount_mem() might be called in asynchronous teardown
contexts where current points to a teardown worker thread instead of the
original VM process. Does this lead to inaccurate uncharging of the
teardown thread?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260727095720.9150-2-borntraeger@linux.ibm.com?part=1
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [GIT PULL 6/7] KVM: s390: pci: Validate AIBV and AISB before pinning guest pages
2026-07-27 9:57 ` [GIT PULL 6/7] KVM: s390: pci: Validate AIBV and AISB before pinning guest pages Christian Borntraeger
@ 2026-07-27 10:18 ` sashiko-bot
0 siblings, 0 replies; 14+ messages in thread
From: sashiko-bot @ 2026-07-27 10:18 UTC (permalink / raw)
To: Christian Borntraeger
Cc: linux-s390, Alexander Gordeev, kvm, Heiko Carstens, Vasily Gorbik
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Missing NULL check for `aisb_page` leads to host memory corruption via a garbage physical address in `gaite->aisb`.
- [Critical] Missing validation of the user-provided `aisbo` allows an out-of-bounds bit flip in host physical memory.
- [High] Missing software state rollback if hardware configuration fails in `kvm_zpci_set_airq()`.
- [High] Missing `kvm_s390_gisc_unregister()` on error paths leaks GISC reference counts.
- [High] No check for already enabled AEN allows guests to leak host resources via repeated ioctl calls.
- [High] Failures in `account_mem()` and `airq_iv_alloc_bit()` return a false success to userspace and leak memory accounting.
- [High] Missing NULL check for `airq_iv_create()` return value leads to host kernel panic.
--
--- Patch [1]: [GIT PULL 6/7] KVM: s390: pci: Validate AIBV and AISB before pinning guest pages ---
commit b6f9e911464048e2480c6dd2f890285a31bef43d
Author: Farhan Ali <alifm@linux.ibm.com>
KVM: s390: pci: Validate AIBV and AISB before pinning guest pages
This commit adds validation checks for the AIBV and AISB addresses provided
by the guest during PCI interrupt forwarding setup. It ensures that the AIBV
does not span more than one page and that the AISB is doubleword aligned.
> diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
> index 5b075c38998e3..efeee49e18ea3 100644
> --- a/arch/s390/kvm/pci.c
> +++ b/arch/s390/kvm/pci.c
> @@ -246,6 +246,14 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
> return gisc;
>
> /* Replace AIBV address */
> + size = BITS_TO_LONGS(msi_vecs + fib->fmt0.aibvo) * sizeof(unsigned long);
> + npages = DIV_ROUND_UP((fib->fmt0.aibv & ~PAGE_MASK) + size, PAGE_SIZE);
> + /* AIBV cannot span more than 1 page */
> + if (npages > 1) {
> + rc = -EINVAL;
> + goto out;
> + }
> +
[Severity: High]
This isn't a bug introduced by this patch, but does the new error path leak
the GISC reference count?
If npages > 1 triggers, the code jumps to out without calling
kvm_s390_gisc_unregister(), which was registered earlier:
gisc = kvm_s390_gisc_register(kvm, fib->fmt0.isc);
if (gisc < 0)
return gisc;
Can a guest repeatedly pass spanning addresses to overflow the reference counter?
> idx = srcu_read_lock(&kvm->srcu);
> hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aibv));
> npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM, pages);
> @@ -261,6 +269,12 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
>
> /* Pin the guest AISB if one was specified */
> if (fib->fmt0.sum == 1) {
> + /* AISB must be dword aligned */
> + if (fib->fmt0.aisb & 0x7) {
> + rc = -EINVAL;
> + goto unpin1;
> + }
> +
[Severity: High]
This is a pre-existing issue, but this alignment check also jumps past the
required unregistration. Should unpin1 or a similar cleanup label handle
the GISC unregistration?
[Severity: High]
This is a pre-existing issue, but I noticed there doesn't seem to be a check
to see if AEN is already enabled on the device.
If a guest repeatedly registers AEN without deregistering first, could the
function allocate new airq_iv structures, pin new guest memory pages, and
overwrite the tracking pointers (zdev->aibv, zdev->aisb), leading to an
exhaustion of host resources?
arch/s390/kvm/pci.c:kvm_s390_pci_aif_enable() {
...
zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA |
AIRQ_IV_BITLOCK |
AIRQ_IV_GUESTVEC,
phys_to_virt(fib->fmt0.aibv));
...
}
[Severity: Critical]
This is a pre-existing issue, but if a guest registers AEN without requesting a
summary bit (fib->fmt0.sum == 0), does aisb_page remain NULL?
If so, later in kvm_s390_pci_aif_enable() we execute:
gaite->aisb = virt_to_phys(page_address(aisb_page) + (fib->fmt0.aisb &
~PAGE_MASK));
This appears to perform pointer arithmetic on page_address(NULL), yielding a
garbage physical address. When the device issues an interrupt, could KVM's
aen_host_forward() see that gaite->aisb != 0 and perform a bit flip on that
garbage address, directly corrupting host memory?
[Severity: High]
This isn't a bug introduced by this patch, but does the error handling for
account_mem() and airq_iv_alloc_bit() return a false success and leak
memory accounting?
arch/s390/kvm/pci.c:kvm_s390_pci_aif_enable() {
...
/* Account for pinned pages, roll back on failure */
if (account_mem(pcount))
goto unpin2;
...
bit = airq_iv_alloc_bit(aift->sbv);
if (bit == -1UL)
goto unlock;
...
}
In both cases, rc seems to remain unassigned (0). Also, it appears the
unlock error path does not call unaccount_mem(pcount).
[Severity: High]
This is a pre-existing issue, but what happens if airq_iv_create() fails and
returns NULL?
arch/s390/kvm/pci.c:kvm_s390_pci_aif_enable() {
...
zdev->aibv = airq_iv_create(msi_vecs, ...);
...
}
It seems zdev->aibv is assigned without a check, and subsequently
kvm_zpci_set_airq() will unconditionally dereference it:
arch/s390/kvm/pci.c:kvm_zpci_set_airq() {
...
fib.fmt0.noi = airq_iv_end(zdev->aibv);
...
}
Could this lead to a NULL pointer dereference panic under host memory pressure?
[Severity: Critical]
This is a pre-existing issue, but is the user-provided aisbo validated
against a 64-bit bounds check?
arch/s390/kvm/pci.c:kvm_s390_pci_aif_enable() {
...
gaite->aisbo = fib->fmt0.aisbo;
...
}
If aisbo is unvalidated and can be up to 255, could KVM's software handler
blindly execute a bit flip crossing into unpinned host physical memory?
arch/s390/kvm/interrupt.c:aen_host_forward() {
...
set_bit_inv(gaite->aisbo, phys_to_virt(gaite->aisb));
...
}
[Severity: High]
This is a pre-existing issue, but if kvm_zpci_set_airq() fails at the very
end of the function, does it bypass the software rollback?
arch/s390/kvm/pci.c:kvm_s390_pci_aif_enable() {
...
/* Issue the clp to setup the irq now */
rc = kvm_zpci_set_airq(zdev);
return rc;
unlock:
...
}
It looks like it returns immediately instead of executing the error cleanup
labels (unpin1, unpin2, unlock), leaving resources leaked.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260727095720.9150-7-borntraeger@linux.ibm.com?part=1
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [GIT PULL 2/7] KVM: s390: pci: Fix memory accounting for pinned/unpinned pages
2026-07-27 10:11 ` sashiko-bot
@ 2026-07-27 11:15 ` Christian Borntraeger
0 siblings, 0 replies; 14+ messages in thread
From: Christian Borntraeger @ 2026-07-27 11:15 UTC (permalink / raw)
To: sashiko-reviews
Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev, kvm
Am 27.07.26 um 12:11 schrieb sashiko-bot@kernel.org:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
>
> New issues:
> - [High] The patch introduces `mm_struct` and `user_struct` reference count leaks on the `airq_iv_alloc_bit()` error path.
For some reason sashiko failed to apply patch3, which fixes this exact problem.
> - [High] Calling the `KVM_S390_ZPCIOP_REG_AEN` ioctl multiple times sequentially overwrites `kzdev->mm_account` and `kzdev->user_account`, permanently leaking the previously acquired kernel object references.
same here. Looks like sashiko applied this series to a wrong tree.
All PCI fixes have been reviewed before here:
https://sashiko.dev/#/patchset/20260723221409.5874-1-alifm%40linux.ibm.com
>
> Pre-existing issues:
> - [High] Missing NULL check for `airq_iv_create()` return value causes a guaranteed NULL pointer dereference.
> --
>
> --- Patch [1]: [GIT PULL 2/7] KVM: s390: pci: Fix memory accounting for pinned/unpinned pages ---
> commit c8a84dcb0557ca0ba1070398f64a0a7a9a08e82b
> Author: Farhan Ali <alifm@linux.ibm.com>
> Date: Mon Jul 27 09:57:15 2026 +0000
>
> KVM: s390: pci: Fix memory accounting for pinned/unpinned pages
>
> This patch stores the pinning process user_struct and mm_struct when
> accounting for pinned pages. It subsequently frees these resources when the
> pages are unpinned to resolve context issues.
>
>> diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
>> index 5b075c38998e3..c2f5085a0f5f1 100644
>> --- a/arch/s390/kvm/pci.c
>> +++ b/arch/s390/kvm/pci.c
> [ ... ]
>> @@ -190,33 +190,54 @@ static int kvm_zpci_clear_airq(struct zpci_dev *zdev)
> [ ... ]
>> -static inline int account_mem(unsigned long nr_pages)
>> +static inline int account_mem(struct kvm_zdev *kzdev, unsigned long nr_pages)
>> {
>> struct user_struct *user = get_uid(current_user());
>> unsigned long page_limit, cur_pages, new_pages;
>> + int rc = 0;
>>
>> page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
>>
>> cur_pages = atomic_long_read(&user->locked_vm);
>> do {
>> new_pages = cur_pages + nr_pages;
>> - if (new_pages > page_limit)
>> - return -ENOMEM;
>> + if (new_pages > page_limit) {
>> + rc = -ENOMEM;
>> + goto out;
>> + }
>> } while (!atomic_long_try_cmpxchg(&user->locked_vm, &cur_pages, new_pages));
>>
>> - atomic64_add(nr_pages, ¤t->mm->pinned_vm);
>> + if (current->mm) {
>> + mmgrab(current->mm);
>> + atomic64_add(nr_pages, ¤t->mm->pinned_vm);
>> + }
>> +
>> + kzdev->user_account = user;
>> + kzdev->mm_account = current->mm;
>
> [Severity: High]
> If the KVM_S390_ZPCIOP_REG_AEN ioctl invokes kvm_s390_pci_aif_enable()
> multiple times sequentially, will this unconditionally overwrite
> kzdev->user_account and kzdev->mm_account?
>
> It appears that if the device is already enabled, the previously acquired
> references would be permanently leaked since unaccount_mem() isn't called
> before assigning the new pointers here.
>
>>
>> return 0;
>> +
>> +out:
>> + free_uid(user);
>> + return rc;
>> }
>>
>> static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
>> @@ -275,7 +296,7 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
>> }
>>
>> /* Account for pinned pages, roll back on failure */
>> - if (account_mem(pcount))
>> + if (account_mem(zdev->kzdev, pcount))
>> goto unpin2;
>>
>> /* AISB must be allocated before we can fill in GAITE */
>
> [Severity: High]
> If airq_iv_alloc_bit() fails later in this function, the error path
> jumps to the unlock and unpin labels:
>
> kvm_s390_pci_aif_enable() {
> ...
> bit = airq_iv_alloc_bit(aift->sbv);
> if (bit == -1UL)
> goto unlock;
> ...
> unlock:
> mutex_unlock(&aift->aift_lock);
> unpin2:
> if (fib->fmt0.sum == 1)
> unpin_user_page(aisb_page);
> ...
> }
>
> Does this error path need to call unaccount_mem() to prevent leaking the
> mm_struct and user_struct references acquired by account_mem() earlier?
>
> [Severity: High]
> This is a pre-existing issue, but is it possible for airq_iv_create() to
> return NULL under memory pressure?
>
> If it fails, zdev->aibv is assigned NULL a bit later in
> kvm_s390_pci_aif_enable():
>
> kvm_s390_pci_aif_enable() {
> ...
> zdev->aibv = airq_iv_create(...);
> ...
> rc = kvm_zpci_set_airq(zdev);
> ...
> }
>
> Could this lead to a NULL pointer dereference when kvm_zpci_set_airq()
> attempts to access airq_iv_end(zdev->aibv)?
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [GIT PULL 0/7] KVM: s390: Fixes for 7.2
2026-07-27 9:57 [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
` (6 preceding siblings ...)
2026-07-27 9:57 ` [GIT PULL 7/7] KVM: s390: Fall back to short-term pinning in MAP ioctl Christian Borntraeger
@ 2026-07-27 11:24 ` Christian Borntraeger
7 siblings, 0 replies; 14+ messages in thread
From: Christian Borntraeger @ 2026-07-27 11:24 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Janosch Frank, Claudio Imbrenda, David Hildenbrand,
linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Sven Schnelle, Matthew Rosato, Jaehoon Kim, Douglas Freimuth,
Farhan Ali
Am 27.07.26 um 11:57 schrieb Christian Borntraeger:
> Paolo,
>
> some more fixes triggered by AI bug reports or testing.
> Mostly for PCI support.
> This also has a regression fix that we introduced in 7.2-rc1
>
> The following changes since commit 3e3aa6da87d30a0064a17b836685cd43c90a3572:
>
> KVM: s390: pci: Fix handling of AIF enable without AISB (2026-07-09 16:23:10 +0200)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git tags/kvm-s390-master-7.2-2
>
> for you to fetch changes up to 9972befc3e34ff8b6847198c84f11bfc312dde40:
>
> KVM: s390: Fall back to short-term pinning in MAP ioctl (2026-07-27 09:23:53 +0200)
>
>
> All fixes had no new sashiko findings, just pre-existing issues or
> finding that are being fixed by other patches of the series.
Paolo,
Sashiko failed to apply some patches. Dont know why, it applies cleanly to v7.2-rc5
and also kvm/master.
This resulted in several false positives as later fixes have not been considered.
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-07-27 11:24 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-27 9:57 [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 1/7] KVM: s390: pci: Reject adapter interrupt forwarding if already enabled Christian Borntraeger
2026-07-27 10:13 ` sashiko-bot
2026-07-27 9:57 ` [GIT PULL 2/7] KVM: s390: pci: Fix memory accounting for pinned/unpinned pages Christian Borntraeger
2026-07-27 10:11 ` sashiko-bot
2026-07-27 11:15 ` Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 3/7] KVM: s390: pci: Fix missing error codes and memory unaccounting Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 4/7] KVM: s390: pci: Fix NULL dereference on AIBV allocation failure Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 5/7] KVM: s390: pci: Fix resource leak on IRQ registration failure Christian Borntraeger
2026-07-27 9:57 ` [GIT PULL 6/7] KVM: s390: pci: Validate AIBV and AISB before pinning guest pages Christian Borntraeger
2026-07-27 10:18 ` sashiko-bot
2026-07-27 9:57 ` [GIT PULL 7/7] KVM: s390: Fall back to short-term pinning in MAP ioctl Christian Borntraeger
2026-07-27 10:10 ` sashiko-bot
2026-07-27 11:24 ` [GIT PULL 0/7] KVM: s390: Fixes for 7.2 Christian Borntraeger
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.