* [PATCH v2 1/6] mm/hugetlb: Fix uffd-wp during fork()
[not found] <20230417195317.898696-1-peterx@redhat.com>
@ 2023-04-17 19:53 ` Peter Xu
2023-04-17 19:53 ` [PATCH v2 2/6] mm/hugetlb: Fix uffd-wp bit lost when unsharing happens Peter Xu
1 sibling, 0 replies; 4+ messages in thread
From: Peter Xu @ 2023-04-17 19:53 UTC (permalink / raw)
To: linux-kernel, linux-mm
Cc: Mike Kravetz, Andrea Arcangeli, Mika Penttilä, Andrew Morton,
peterx, Axel Rasmussen, Nadav Amit, David Hildenbrand,
linux-stable
There're a bunch of things that were wrong:
- Reading uffd-wp bit from a swap entry should use pte_swp_uffd_wp()
rather than huge_pte_uffd_wp().
- When copying over a pte, we should drop uffd-wp bit when
!EVENT_FORK (aka, when !userfaultfd_wp(dst_vma)).
- When doing early CoW for private hugetlb (e.g. when the parent page was
pinned), uffd-wp bit should be properly carried over if necessary.
No bug reported probably because most people do not even care about these
corner cases, but they are still bugs and can be exposed by the recent unit
tests introduced, so fix all of them in one shot.
Cc: linux-stable <stable@vger.kernel.org>
Fixes: bc70fbf269fd ("mm/hugetlb: handle uffd-wp during fork()")
Reviewed-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
mm/hugetlb.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index f16b25b1a6b9..0213efaf31be 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -4953,11 +4953,15 @@ static bool is_hugetlb_entry_hwpoisoned(pte_t pte)
static void
hugetlb_install_folio(struct vm_area_struct *vma, pte_t *ptep, unsigned long addr,
- struct folio *new_folio)
+ struct folio *new_folio, pte_t old)
{
+ pte_t newpte = make_huge_pte(vma, &new_folio->page, 1);
+
__folio_mark_uptodate(new_folio);
hugepage_add_new_anon_rmap(new_folio, vma, addr);
- set_huge_pte_at(vma->vm_mm, addr, ptep, make_huge_pte(vma, &new_folio->page, 1));
+ if (userfaultfd_wp(vma) && huge_pte_uffd_wp(old))
+ newpte = huge_pte_mkuffd_wp(newpte);
+ set_huge_pte_at(vma->vm_mm, addr, ptep, newpte);
hugetlb_count_add(pages_per_huge_page(hstate_vma(vma)), vma->vm_mm);
folio_set_hugetlb_migratable(new_folio);
}
@@ -5032,14 +5036,12 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
*/
;
} else if (unlikely(is_hugetlb_entry_hwpoisoned(entry))) {
- bool uffd_wp = huge_pte_uffd_wp(entry);
-
- if (!userfaultfd_wp(dst_vma) && uffd_wp)
+ if (!userfaultfd_wp(dst_vma))
entry = huge_pte_clear_uffd_wp(entry);
set_huge_pte_at(dst, addr, dst_pte, entry);
} else if (unlikely(is_hugetlb_entry_migration(entry))) {
swp_entry_t swp_entry = pte_to_swp_entry(entry);
- bool uffd_wp = huge_pte_uffd_wp(entry);
+ bool uffd_wp = pte_swp_uffd_wp(entry);
if (!is_readable_migration_entry(swp_entry) && cow) {
/*
@@ -5050,10 +5052,10 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
swp_offset(swp_entry));
entry = swp_entry_to_pte(swp_entry);
if (userfaultfd_wp(src_vma) && uffd_wp)
- entry = huge_pte_mkuffd_wp(entry);
+ entry = pte_swp_mkuffd_wp(entry);
set_huge_pte_at(src, addr, src_pte, entry);
}
- if (!userfaultfd_wp(dst_vma) && uffd_wp)
+ if (!userfaultfd_wp(dst_vma))
entry = huge_pte_clear_uffd_wp(entry);
set_huge_pte_at(dst, addr, dst_pte, entry);
} else if (unlikely(is_pte_marker(entry))) {
@@ -5114,7 +5116,8 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
/* huge_ptep of dst_pte won't change as in child */
goto again;
}
- hugetlb_install_folio(dst_vma, dst_pte, addr, new_folio);
+ hugetlb_install_folio(dst_vma, dst_pte, addr,
+ new_folio, src_pte_old);
spin_unlock(src_ptl);
spin_unlock(dst_ptl);
continue;
@@ -5132,6 +5135,9 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
entry = huge_pte_wrprotect(entry);
}
+ if (!userfaultfd_wp(dst_vma))
+ entry = huge_pte_clear_uffd_wp(entry);
+
set_huge_pte_at(dst, addr, dst_pte, entry);
hugetlb_count_add(npages, dst);
}
--
2.39.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/6] mm/hugetlb: Fix uffd-wp bit lost when unsharing happens
[not found] <20230417195317.898696-1-peterx@redhat.com>
2023-04-17 19:53 ` [PATCH v2 1/6] mm/hugetlb: Fix uffd-wp during fork() Peter Xu
@ 2023-04-17 19:53 ` Peter Xu
2023-04-17 23:48 ` Andrew Morton
1 sibling, 1 reply; 4+ messages in thread
From: Peter Xu @ 2023-04-17 19:53 UTC (permalink / raw)
To: linux-kernel, linux-mm
Cc: Mike Kravetz, Andrea Arcangeli, Mika Penttilä, Andrew Morton,
peterx, Axel Rasmussen, Nadav Amit, David Hildenbrand,
linux-stable
When we try to unshare a pinned page for a private hugetlb, uffd-wp bit can
get lost during unsharing. Fix it by carrying it over.
This should be very rare, only if an unsharing happened on a private
hugetlb page with uffd-wp protected (e.g. in a child which shares the same
page with parent with UFFD_FEATURE_EVENT_FORK enabled).
Cc: linux-stable <stable@vger.kernel.org>
Fixes: 166f3ecc0daf ("mm/hugetlb: hook page faults for uffd write protection")
Reported-by: Mike Kravetz <mike.kravetz@oracle.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Mike Kravetz <mike.kravetz@oracle.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
mm/hugetlb.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 0213efaf31be..cd3a9d8f4b70 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -5637,13 +5637,16 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,
spin_lock(ptl);
ptep = hugetlb_walk(vma, haddr, huge_page_size(h));
if (likely(ptep && pte_same(huge_ptep_get(ptep), pte))) {
+ pte_t newpte = make_huge_pte(vma, &new_folio->page, !unshare);
+
/* Break COW or unshare */
huge_ptep_clear_flush(vma, haddr, ptep);
mmu_notifier_invalidate_range(mm, range.start, range.end);
page_remove_rmap(old_page, vma, true);
hugepage_add_new_anon_rmap(new_folio, vma, haddr);
- set_huge_pte_at(mm, haddr, ptep,
- make_huge_pte(vma, &new_folio->page, !unshare));
+ if (huge_pte_uffd_wp(pte))
+ newpte = huge_pte_mkuffd_wp(newpte);
+ set_huge_pte_at(mm, haddr, ptep, newpte);
folio_set_hugetlb_migratable(new_folio);
/* Make the old page be freed below */
new_folio = page_folio(old_page);
--
2.39.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 2/6] mm/hugetlb: Fix uffd-wp bit lost when unsharing happens
2023-04-17 19:53 ` [PATCH v2 2/6] mm/hugetlb: Fix uffd-wp bit lost when unsharing happens Peter Xu
@ 2023-04-17 23:48 ` Andrew Morton
2023-04-18 15:14 ` Peter Xu
0 siblings, 1 reply; 4+ messages in thread
From: Andrew Morton @ 2023-04-17 23:48 UTC (permalink / raw)
To: Peter Xu
Cc: linux-kernel, linux-mm, Mike Kravetz, Andrea Arcangeli,
Mika Penttilä, Axel Rasmussen, Nadav Amit, David Hildenbrand,
linux-stable
On Mon, 17 Apr 2023 15:53:13 -0400 Peter Xu <peterx@redhat.com> wrote:
> When we try to unshare a pinned page for a private hugetlb, uffd-wp bit can
> get lost during unsharing. Fix it by carrying it over.
>
> This should be very rare, only if an unsharing happened on a private
> hugetlb page with uffd-wp protected (e.g. in a child which shares the same
> page with parent with UFFD_FEATURE_EVENT_FORK enabled).
What are the user-visible consequences of the bug?
> Cc: linux-stable <stable@vger.kernel.org>
When proposing a backport, it's better to present the patch as a
standalone thing, against current -linus. I'll then queue it in
mm-hotfixes and shall send it upstream during this -rc cycle.
As presented, this patch won't go upstream until after 6.3 is released,
and as it comes later in time, more backporting effort might be needed.
I can rework things if this fix is reasonably urgent (the "user-visible
consequences" info is the guide). If not urgent, we can leave things
as they are.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2 2/6] mm/hugetlb: Fix uffd-wp bit lost when unsharing happens
2023-04-17 23:48 ` Andrew Morton
@ 2023-04-18 15:14 ` Peter Xu
0 siblings, 0 replies; 4+ messages in thread
From: Peter Xu @ 2023-04-18 15:14 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-kernel, linux-mm, Mike Kravetz, Andrea Arcangeli,
Mika Penttilä, Axel Rasmussen, Nadav Amit, David Hildenbrand,
linux-stable
Hi, Andrew,
On Mon, Apr 17, 2023 at 04:48:22PM -0700, Andrew Morton wrote:
> On Mon, 17 Apr 2023 15:53:13 -0400 Peter Xu <peterx@redhat.com> wrote:
>
> > When we try to unshare a pinned page for a private hugetlb, uffd-wp bit can
> > get lost during unsharing. Fix it by carrying it over.
> >
> > This should be very rare, only if an unsharing happened on a private
> > hugetlb page with uffd-wp protected (e.g. in a child which shares the same
> > page with parent with UFFD_FEATURE_EVENT_FORK enabled).
>
> What are the user-visible consequences of the bug?
When above condition met, one can lose uffd-wp bit on the privately mapped
hugetlb page. It allows the page to be writable even if it should still be
wr-protected. I assume it can mean data loss.
However it's very hard to trigger. When I wrote the reproducer (provided in
the last patch) I needed to use the newest gup_test cmd introduced by David
to trigger it because I don't even know another way to do a proper RO
longerm pin.
Besides that, it needs a bunch of other conditions all met:
(1) hugetlb being mapped privately,
(2) userfaultfd registered with WP and EVENT_FORK,
(3) the user app fork()s, then,
(4) RO longterm pin onto a wr-protected anonymous page.
If it's not impossible to hit in production I'd say extremely rare.
>
> > Cc: linux-stable <stable@vger.kernel.org>
>
> When proposing a backport, it's better to present the patch as a
> standalone thing, against current -linus. I'll then queue it in
> mm-hotfixes and shall send it upstream during this -rc cycle.
>
> As presented, this patch won't go upstream until after 6.3 is released,
> and as it comes later in time, more backporting effort might be needed.
>
> I can rework things if this fix is reasonably urgent (the "user-visible
> consequences" info is the guide). If not urgent, we can leave things
> as they are.
IMHO it's not urgent so suitable for mm-unstable (current base of this set;
sorry if I forgot to mention it explicitly). I'll post (and remember to
post) patches on top of mm-stable if they're urgent, or e.g. bugs
introduced in current release.
I copied stable for the pure logic of fixing a bug in old kernels. The
consequence of hitting the bug is very bad but chance to hit is very low.
Thanks,
--
Peter Xu
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2023-04-18 15:15 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20230417195317.898696-1-peterx@redhat.com>
2023-04-17 19:53 ` [PATCH v2 1/6] mm/hugetlb: Fix uffd-wp during fork() Peter Xu
2023-04-17 19:53 ` [PATCH v2 2/6] mm/hugetlb: Fix uffd-wp bit lost when unsharing happens Peter Xu
2023-04-17 23:48 ` Andrew Morton
2023-04-18 15:14 ` Peter Xu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox