linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 6.1] mm/mprotect: restore pmd stability check in change_pte_range()
@ 2026-01-14 18:57 Fedor Pchelkin
  0 siblings, 0 replies; only message in thread
From: Fedor Pchelkin @ 2026-01-14 18:57 UTC (permalink / raw)
  To: Harry Yoo, David Hildenbrand, Greg Kroah-Hartman, stable
  Cc: Fedor Pchelkin, Andrew Morton, Hugh Dickins, linux-mm,
	linux-kernel, lvc-project

No upstream commit exists for this patch.

There is a crash which started to be observed on 6.1.y kernel after
backporting a modified version of commit 670ddd8cdcbd ("mm/mprotect:
delete pmd_none_or_clear_bad_unless_trans_huge()").

general protection fault, probably for non-canonical address 0xdffffc0000000003: 0000 [#1] PREEMPT SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000018-0x000000000000001f]
CPU: 0 PID: 23316 Comm: syz-executor.6 Not tainted 6.1.160-syzkaller-00409-g94ae58088937 #0
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:__lock_acquire+0xdc2/0x5320 kernel/locking/lockdep.c:4919
Call Trace:
 <TASK>
 lock_acquire kernel/locking/lockdep.c:5662 [inline]
 lock_acquire+0x194/0x4b0 kernel/locking/lockdep.c:5627
 __raw_spin_lock include/linux/spinlock_api_smp.h:133 [inline]
 _raw_spin_lock+0x27/0x40 kernel/locking/spinlock.c:154
 spin_lock include/linux/spinlock.h:351 [inline]
 change_pte_range mm/mprotect.c:91 [inline]
 change_pmd_range mm/mprotect.c:401 [inline]
 change_pud_range mm/mprotect.c:432 [inline]
 change_p4d_range mm/mprotect.c:453 [inline]
 change_protection_range mm/mprotect.c:477 [inline]
 change_protection+0xa1f/0x35e0 mm/mprotect.c:499
 uffd_wp_range+0xf8/0x190 mm/userfaultfd.c:748
 userfaultfd_unregister fs/userfaultfd.c:1646 [inline]
 userfaultfd_ioctl+0x38a7/0x46d0 fs/userfaultfd.c:2037
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:870 [inline]
 __se_sys_ioctl fs/ioctl.c:856 [inline]
 __x64_sys_ioctl+0x19a/0x210 fs/ioctl.c:856
 do_syscall_x64 arch/x86/entry/common.c:46 [inline]
 do_syscall_64+0x35/0x80 arch/x86/entry/common.c:76

The reason is that a pmd_none entry made its way into
pte_offset_map_lock().  It crashes when USE_SPLIT_PTE_PTLOCKS is set.

It seems that pmd_trans_unstable() check shouldn't have been removed from
the 6.1.y version of the patch, restore it.  Upstream code, starting with
commit 0d940a9b270b ("mm/pgtable: allow pte_offset_map[_lock]() to fail"),
has internal checks for that inside pte_offset_map_lock() itself.

Found by Linux Verification Center (linuxtesting.org) with Syzkaller.

Fixes: 670ddd8cdcbd ("mm/mprotect: delete pmd_none_or_clear_bad_unless_trans_huge()")
Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
---

I've tried to follow the original discussion [1] regarding the problem
this backport is supposed to solve and how it was tweaked for stable
inclusion but failed to find whether the pmd_trans_unstable() check was
dropped accidentaly (because upstream commit does remove it as well) or
there was some reasoning behind it.

The backport patch is already in 6.1.160 release so I guess the fix should
be added to 6.1.y branch directly.  Looking forward for your review and
comments on the problem, thanks!  I can provide .config and reproducer if
needed.

The backport patches are currently in queue for 5.10 and 5.15 kernels
inclusion so they still may be dropped from there and reworked accordingly.

[1]: https://lore.kernel.org/linux-mm/20250921232709.1608699-1-harry.yoo@oracle.com/
[2]: https://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git/

 mm/mprotect.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/mm/mprotect.c b/mm/mprotect.c
index f09229fbcf6c..ef6a360ec088 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -88,6 +88,15 @@ static long change_pte_range(struct mmu_gather *tlb,
 
 	tlb_change_page_size(tlb, PAGE_SIZE);
 
+	/*
+	 * Can be called with only the mmap_lock for reading by
+	 * prot_numa so we must check the pmd isn't constantly
+	 * changing from under us from pmd_none to pmd_trans_huge
+	 * and/or the other way around.
+	 */
+	if (pmd_trans_unstable(pmd))
+		return 0;
+
 	pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
 	/* Make sure pmd didn't change after acquiring ptl */
 	_pmd = pmd_read_atomic(pmd);
-- 
2.51.0



^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-01-15  0:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-14 18:57 [PATCH 6.1] mm/mprotect: restore pmd stability check in change_pte_range() Fedor Pchelkin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox