From: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
To: Konstantin Khorenko <khorenko@virtuozzo.com>,
Andrew Morton <akpm@linux-foundation.org>,
"David Hildenbrand (Arm)" <david@kernel.org>,
Zi Yan <ziy@nvidia.com>,
Baolin Wang <baolin.wang@linux.alibaba.com>,
"Liam R. Howlett" <liam@infradead.org>,
Nico Pache <nico.pache@linux.dev>,
Ryan Roberts <ryan.roberts@arm.com>, Dev Jain <dev.jain@arm.com>,
Barry Song <baohua@kernel.org>, Lance Yang <lance.yang@linux.dev>,
Usama Arif <usama.arif@linux.dev>,
Kiryl Shutsemau <kas@kernel.org>, Peter Xu <peterx@redhat.com>
Cc: "Alex Williamson" <alex@shazbot.org>,
kvm@vger.kernel.org,
"Loïc Molinari" <loic.molinari@collabora.com>,
"Lorenzo Stoakes" <ljs@kernel.org>,
"Shuah Khan" <shuah@kernel.org>,
linux-kselftest@vger.kernel.org, dri-devel@lists.freedesktop.org,
"Madhavan Srinivasan" <maddy@linux.ibm.com>,
linuxppc-dev@lists.ozlabs.org, linux-mm@kvack.org,
linux-kernel@vger.kernel.org,
"Konstantin Khorenko" <khorenko@virtuozzo.com>,
"Jason Gunthorpe" <jgg@ziepe.ca>,
stable@vger.kernel.org, Sashiko <sashiko-bot@kernel.org>
Subject: Re: [PATCH v5 3/4] mm/huge_memory: read a special PMD under the lock in copy_huge_pmd()
Date: Tue, 10 Nov 2026 08:30:44 +0530 [thread overview]
Message-ID: <pkwd8k6b.ritesh.list@gmail.com> (raw)
In-Reply-To: <20261104-b4-prep-vstor-149847-copy_huge_pmd-recheck-special-pmd-v5-3-c56d0d26f970@virtuozzo.com>
Konstantin Khorenko <khorenko@virtuozzo.com> writes:
> copy_huge_pmd() reads a special PMD without the page table lock and
> copies that value to the child. The mmap write lock held by fork does
> not stop unmap_mapping_range(): it zaps under i_mmap_rwsem and the PMD
> lock.
>
> The zap visits the parent VMA before the child's, as dup_mmap() links
> the child right after the parent in i_mmap. If it clears the parent PMD
> after fork has read it, and passes the child before fork copies it, the
> child keeps a mapping the driver has revoked, for example:
>
> - vfio-pci: the child reaches the BAR after the device memory was
> disabled or the device was reset, instead of getting SIGBUS;
> - panthor: the child maps the pages of an evicted buffer object after
> the driver has released them.
>
> The same branch deposits no page table under the copy. ppc64 in hash
> mode keeps the hash slot array of every huge PMD in that table, so the
> child dereferences a NULL table on the first hash fault, in
> __hash_page_thp(), and on the zap, in hash__pmdp_huge_get_and_clear().
>
> Take the locks first and let vm_normal_page_pmd() tell a PFN mapping
> from a folio under them, as copy_present_ptes() does with
> vm_normal_page(). The zap clears the parent PMD under the same lock, so
> either fork finds it none and skips it, or the copy is in place before
> the zap reaches the child.
>
> The copy of a PFN mapping then goes through the same tail as a folio:
>
> - it gets a page table where the architecture needs one;
> - in a shared mapping it is marked clean in the child, as a PTE is;
> - in a CoW mapping, which only VM_MIXEDMAP allows, both sides are write
> protected instead of a warning being printed.
>
> Fixes: bc02afbd4d73 ("mm/fork: accept huge pfnmap entries")
> Fixes: d1503aa9ab80 ("powerpc/64s: Add support for huge pfnmaps")
Thanks Konstantin, for fixing this. Without this patch I can reproduce the problem on Hash
on Power (on my test dev setup), after fork(), when child touches those pages.
[ 62.543247][ T242] Kernel attempted to read user page (0) - exploit attempt? (uid: 0)
[ 62.544992][ T242] BUG: Kernel NULL pointer dereference on read at 0x00000000
[ 62.545335][ T242] Faulting instruction address: 0xc0000000000a0ee8
cpu 0x0: Vector: 300 (Data Access) at [c00000002035f9d0]
pc: c0000000000a0ee8: __hash_page_thp+0x218/0x560
lr: c0000000000a0e14: __hash_page_thp+0x144/0x560
sp: c00000002035fc70
msr: 8000000000009033
dar: 0
dsisr: 40000000
current = 0xc00000001fb08480
paca = 0xc000000005010000 irqmask: 0x03 irq_happened: 0x09
pid = 242, comm = vfio-fork
enter ? for help
[c00000002035fc70] 0000000000000000 (unreliable)
[c00000002035fd30] c000000000098a40 hash_page_mm+0x688/0x8d0
[c00000002035fe10] c000000000098dc8 do_hash_fault+0x140/0x368
[c00000002035fe50] c000000000008be0 data_access_common_virt+0x210/0x220
---- Exception: 300 (Data Access) at 0000000010001b60
SP (7fffde6dd7b0) is in userspace
With this series, I see that the issue is fixed. Thanks for helping in
fixing it. Please feel free to add:
Tested-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com> #PowerPC
> Cc: stable@vger.kernel.org
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://sashiko.dev/#/patchset/20261014-b4-prep-vstor-149847-copy_huge_pmd-recheck-special-pmd-v1-1-d225c60bc316@virtuozzo.com?part=1
> Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
> Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
> Acked-by: David Hildenbrand (Arm) <david@kernel.org>
> Signed-off-by: Konstantin Khorenko <khorenko@virtuozzo.com>
> ---
> mm/huge_memory.c | 24 +++---------------------
> 1 file changed, 3 insertions(+), 21 deletions(-)
>
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index e00632edb3856..9cb5f99aba87f 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -1961,25 +1961,6 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
> int ret = -ENOMEM;
> bool writable;
>
> - pmd = pmdp_get_lockless(src_pmd);
> - if (unlikely(pmd_present(pmd) && pmd_special(pmd) &&
> - !is_huge_zero_pmd(pmd))) {
> - dst_ptl = pmd_lock(dst_mm, dst_pmd);
> - src_ptl = pmd_lockptr(src_mm, src_pmd);
> - spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
> - /*
> - * No need to recheck the pmd, it can't change with write
> - * mmap lock held here.
> - *
> - * Meanwhile, making sure it's not a CoW VMA with writable
> - * mapping, otherwise it means either the anon page wrongly
> - * applied special bit, or we made the PRIVATE mapping be
> - * able to wrongly write to the backend MMIO.
> - */
> - VM_WARN_ON_ONCE(vma_is_cow_mapping(src_vma) && pmd_write(pmd));
> - goto set_pmd;
> - }
> -
> if (vma_is_anonymous(dst_vma) || arch_needs_pgtable_deposit()) {
> pgtable = pte_alloc_one(dst_mm);
> if (unlikely(!pgtable))
> @@ -2021,7 +2002,9 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
> goto copy_pmd;
> }
>
> - src_page = pmd_page(pmd);
> + src_page = vm_normal_page_pmd(src_vma, addr, pmd);
> + if (!src_page)
> + goto copy_pmd;
> VM_BUG_ON_PAGE(!PageHead(src_page), src_page);
> src_folio = page_folio(src_page);
>
> @@ -2061,7 +2044,6 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
> }
> if (src_vma->vm_flags & VM_SHARED)
> pmd = pmd_mkclean(pmd);
> -set_pmd:
> pmd = pmd_mkold(pmd);
> set_pmd_at(dst_mm, addr, dst_pmd, pmd);
>
>
> --
> 2.43.0
next prev parent reply other threads:[~2026-11-10 3:22 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-04 20:40 [PATCH v5 0/4] mm/huge_memory: copy PMDs at fork like the PTE path does Konstantin Khorenko
2026-11-04 20:40 ` [PATCH v5 1/4] mm/rmap: duplicate a PMD mapping as one in folio_dup_file_rmap_pmd() Konstantin Khorenko
2026-11-04 22:57 ` Jose A. Perez de Azpillaga
2026-11-04 20:40 ` [PATCH v5 2/4] mm/huge_memory: copy file THPs at fork like copy_present_ptes() does Konstantin Khorenko
2026-11-04 23:05 ` Jose A. Perez de Azpillaga
2026-11-06 3:04 ` Zi Yan
2026-11-04 20:40 ` [PATCH v5 3/4] mm/huge_memory: read a special PMD under the lock in copy_huge_pmd() Konstantin Khorenko
2026-11-04 23:09 ` Jose A. Perez de Azpillaga
2026-11-06 3:07 ` Zi Yan
2026-11-10 3:00 ` Ritesh Harjani [this message]
2026-11-04 20:40 ` [PATCH v5 4/4] selftests/mm: test fork of PMD-mapped shmem THPs Konstantin Khorenko
2026-11-04 23:15 ` Jose A. Perez de Azpillaga
2026-11-05 13:15 ` Konstantin Khorenko
2026-11-06 5:18 ` [PATCH v5 0/4] mm/huge_memory: copy PMDs at fork like the PTE path does Andrew Morton
2026-11-06 16:48 ` Andrew Morton
2026-11-06 16:59 ` Konstantin Khorenko
2026-11-06 21:28 ` David Hildenbrand (Arm)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pkwd8k6b.ritesh.list@gmail.com \
--to=ritesh.list@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=alex@shazbot.org \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=david@kernel.org \
--cc=dev.jain@arm.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=jgg@ziepe.ca \
--cc=kas@kernel.org \
--cc=khorenko@virtuozzo.com \
--cc=kvm@vger.kernel.org \
--cc=lance.yang@linux.dev \
--cc=liam@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=ljs@kernel.org \
--cc=loic.molinari@collabora.com \
--cc=maddy@linux.ibm.com \
--cc=nico.pache@linux.dev \
--cc=peterx@redhat.com \
--cc=ryan.roberts@arm.com \
--cc=sashiko-bot@kernel.org \
--cc=shuah@kernel.org \
--cc=stable@vger.kernel.org \
--cc=usama.arif@linux.dev \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.