]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: s390: Fix gmap_helper_zap_one_page() again
authorClaudio Imbrenda <imbrenda@linux.ibm.com>
Wed, 31 Dec 2025 03:16:26 +0000 (22:16 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 8 Jan 2026 09:16:41 +0000 (10:16 +0100)
[ Upstream commit 2f393c228cc519ddf19b8c6c05bf15723241aa96 ]

A few checks were missing in gmap_helper_zap_one_page(), which can lead
to memory corruption in the guest under specific circumstances.

Add the missing checks.

Fixes: 5deafa27d9ae ("KVM: s390: Fix to clear PTE when discarding a swapped page")
Cc: stable@vger.kernel.org
Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Tested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
[ adapted ptep_zap_softleaf_entry() and softleaf_from_pte() calls to ptep_zap_swap_entry() and pte_to_swp_entry() ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/s390/mm/gmap_helpers.c

index d4c3c36855e26c74f261316df09a810188304925..38a2d82cd88a7a0d57a020bcadc1c6b98ea38e40 100644 (file)
@@ -47,6 +47,7 @@ static void ptep_zap_swap_entry(struct mm_struct *mm, swp_entry_t entry)
 void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr)
 {
        struct vm_area_struct *vma;
+       unsigned long pgstev;
        spinlock_t *ptl;
        pgste_t pgste;
        pte_t *ptep;
@@ -65,9 +66,13 @@ void gmap_helper_zap_one_page(struct mm_struct *mm, unsigned long vmaddr)
        if (pte_swap(*ptep)) {
                preempt_disable();
                pgste = pgste_get_lock(ptep);
+               pgstev = pgste_val(pgste);
 
-               ptep_zap_swap_entry(mm, pte_to_swp_entry(*ptep));
-               pte_clear(mm, vmaddr, ptep);
+               if ((pgstev & _PGSTE_GPS_USAGE_MASK) == _PGSTE_GPS_USAGE_UNUSED ||
+                   (pgstev & _PGSTE_GPS_ZERO)) {
+                       ptep_zap_swap_entry(mm, pte_to_swp_entry(*ptep));
+                       pte_clear(mm, vmaddr, ptep);
+               }
 
                pgste_set_unlock(ptep, pgste);
                preempt_enable();