Skip to content

Commit 1a5b6f1

Browse files
committed
mm/hugetlb: don't map folios writable without VM_WRITE when copying during fork()
commit d8fd84d Author: David Hildenbrand <[email protected]> Date: Wed Dec 4 16:31:00 2024 +0100 mm/hugetlb: don't map folios writable without VM_WRITE when copying during fork() If we have to trigger a hugetlb folio copy during fork() because the anon folio might be pinned, we currently unconditionally create a writable PTE. However, the VMA might not have write permissions (VM_WRITE) at that point. Fix it by checking the VMA for VM_WRITE. Make the code less error prone by moving checking for VM_WRITE into make_huge_pte(), and letting callers only specify whether we should try making it writable. A simple reproducer that longterm-pins the folios using liburing to then mprotect(PROT_READ) the folios befor fork() [1] results in: Before: [FAIL] access should not have worked After: [PASS] access did not work as expected [1] https://gitlab.com/davidhildenbrand/scratchspace/-/raw/main/reproducers/hugetlb-mkwrite-fork.c This is rather a corner case, so stable might not be warranted. Link: https://lkml.kernel.org/r/[email protected] Fixes: 4eae4ef ("hugetlb: do early cow when page pinned on src mm") Signed-off-by: David Hildenbrand <[email protected]> Acked-by: Peter Xu <[email protected]> Cc: Muchun Song <[email protected]> Cc: Guillaume Morin <[email protected]> Signed-off-by: Andrew Morton <[email protected]> JIRA: https://issues.redhat.com/browse/RHEL-77742 Signed-off-by: Nico Pache <[email protected]>
1 parent f90dcc8 commit 1a5b6f1

File tree

1 file changed

+6
-12
lines changed

1 file changed

+6
-12
lines changed

mm/hugetlb.c

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5155,12 +5155,12 @@ const struct vm_operations_struct hugetlb_vm_ops = {
51555155
};
51565156

51575157
static pte_t make_huge_pte(struct vm_area_struct *vma, struct page *page,
5158-
int writable)
5158+
bool try_mkwrite)
51595159
{
51605160
pte_t entry;
51615161
unsigned int shift = huge_page_shift(hstate_vma(vma));
51625162

5163-
if (writable) {
5163+
if (try_mkwrite && (vma->vm_flags & VM_WRITE)) {
51645164
entry = huge_pte_mkwrite(huge_pte_mkdirty(mk_huge_pte(page,
51655165
vma->vm_page_prot)));
51665166
} else {
@@ -5213,7 +5213,7 @@ static void
52135213
hugetlb_install_folio(struct vm_area_struct *vma, pte_t *ptep, unsigned long addr,
52145214
struct folio *new_folio, pte_t old, unsigned long sz)
52155215
{
5216-
pte_t newpte = make_huge_pte(vma, &new_folio->page, 1);
5216+
pte_t newpte = make_huge_pte(vma, &new_folio->page, true);
52175217

52185218
__folio_mark_uptodate(new_folio);
52195219
hugetlb_add_new_anon_rmap(new_folio, vma, addr);
@@ -6249,8 +6249,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping,
62496249
hugetlb_add_new_anon_rmap(folio, vma, vmf->address);
62506250
else
62516251
hugetlb_add_file_rmap(folio);
6252-
new_pte = make_huge_pte(vma, &folio->page, ((vma->vm_flags & VM_WRITE)
6253-
&& (vma->vm_flags & VM_SHARED)));
6252+
new_pte = make_huge_pte(vma, &folio->page, vma->vm_flags & VM_SHARED);
62546253
/*
62556254
* If this pte was previously wr-protected, keep it wr-protected even
62566255
* if populated.
@@ -6582,7 +6581,6 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
65826581
spinlock_t *ptl;
65836582
int ret = -ENOMEM;
65846583
struct folio *folio;
6585-
int writable;
65866584
bool folio_in_pagecache = false;
65876585

65886586
if (uffd_flags_mode_is(flags, MFILL_ATOMIC_POISON)) {
@@ -6736,12 +6734,8 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
67366734
* For either: (1) CONTINUE on a non-shared VMA, or (2) UFFDIO_COPY
67376735
* with wp flag set, don't set pte write bit.
67386736
*/
6739-
if (wp_enabled || (is_continue && !vm_shared))
6740-
writable = 0;
6741-
else
6742-
writable = dst_vma->vm_flags & VM_WRITE;
6743-
6744-
_dst_pte = make_huge_pte(dst_vma, &folio->page, writable);
6737+
_dst_pte = make_huge_pte(dst_vma, &folio->page,
6738+
!wp_enabled && !(is_continue && !vm_shared));
67456739
/*
67466740
* Always mark UFFDIO_COPY page dirty; note that this may not be
67476741
* extremely important for hugetlbfs for now since swapping is not

0 commit comments

Comments
 (0)