From 769417e410dd19b2a438c6addb61b194b7a4c387 Mon Sep 17 00:00:00 2001 From: "David Hildenbrand (Arm)" Date: Fri, 23 Oct 2026 14:47:28 +0100 Subject: [PATCH] mm/vma: write lock source VMA before duplicating it in __split_vma() __split_vma() duplicates the source VMA before taking its VMA write lock, and until the VMA is write-locked, a concurrent thread might set VMA_MAYBE_GUARD_BIT, resulting in the duplication missing the flag. If this happens, then fork may fail to duplicate guard markers and, if a file-backed mapping, THP collapse may also discard the markers. Resolve this by taking the VMA write lock before vm_area_dup() and, since all callers of vm_area_dup() now hold the VMA write lock, assert that this is the case there, and add a comment to explain why it's needed. [ljs@kernel.org: add VMA write assert in vm_area_dup(), commit message touchup] Link: https://lore.kernel.org/20261023-fix-vma-atomic-v1-2-8ff4fae1fc85@kernel.org Fixes: 2ab7f1bbafc9 ("mm/madvise: allow guard page install/remove under VMA lock") Signed-off-by: David Hildenbrand (Arm) Signed-off-by: Lorenzo Stoakes (ARM) Signed-off-by: Andrew Morton Reviewed-by: Lorenzo Stoakes (ARM) Reviewed-by: Davidlohr Bueso Reviewed-by: Pedro Falcato Tested-by: Gregory Price (Meta) Cc: Liam R. Howlett Cc: Vlastimil Babka Cc: Mike Rapoport Cc: Suren Baghdasaryan Cc: Michal Hocko Cc: Jann Horn Cc: SJ Park Cc: Kees Cook Cc: Colin Cross Cc: --- mm/vma.c | 2 +- mm/vma_init.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/vma.c b/mm/vma.c index 88ef92ab24ec..0325b3979313 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -538,6 +538,7 @@ __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma, return err; } + vma_start_write(vma); new = vm_area_dup(vma); if (!new) return -ENOMEM; @@ -568,7 +569,6 @@ __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma, if (new->vm_ops && new->vm_ops->open) new->vm_ops->open(new); - vma_start_write(vma); vma_start_write(new); init_vma_prep(&vp, vma); diff --git a/mm/vma_init.c b/mm/vma_init.c index baa7e82f47e3..d661f229a734 100644 --- a/mm/vma_init.c +++ b/mm/vma_init.c @@ -127,6 +127,9 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig) { struct vm_area_struct *new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + /* Must hold a write lock to stabilise atomic VMA flags. */ + vma_assert_write_locked(orig); + if (!new) return NULL;