From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1792781047; b=MIc1tP1jWv7+RgjX0GOPW8HeDe61Xi9TDYkUBokIe3f/JFFo26vW0dqmpvne1ETQ9XAk zYKbrZwhg00p9NKKyn26DlMvrryk7YYbwONtcz0S6GHdqTXib0KXIPtC9eDT0ARS5nJ38 uhVEvD4GJluzzeeGSDBr3WZMluu5/128lHmC4bL0/uxnsI0kJZfdBs9aIJHtYpDb/iJUS x3mgrdNYbiW04IkwcG/1L1+BY6layZWlAERYwHw3Iff6pcLopomZfIqaIHEi2UBINMTpa WsZM/1RtpcDmUq5HUc5My+4LonoAQ00bX/GWMywfyAZiuhZ4GZ86lPo0F0CDF9Kgufg== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1792781047; h=Received:DKIM-Signature:Date:To:From:Subject:Message-Id; bh=sxJRzimCkfr7PoRzvdbf9zo+BJKYvlRk+qSTPyzrglc=; b=UFZVHWswkTxhWY6OX/acQpW8eeeXiuNIaQpuqKdmV42Ry9hLRjKs7Cci/oplED8Fh7i5 mqHqzahHiWNPV/akd9peaEtWaFlacg7YPzN0nC2lRs7TL6Q2q3Di5sdtKmnmYIZqLrpwd Fy91D9QywSN2FQNEq2iFoVdXb3/tx6CINbYIGjxv8g58v4yd90jMThzzw8lZS90uLcxss DDOlsmDstPvfPgH7wPwF1bRqAZh3/36W41ZDqd+e84MxWslXxin+rERs1SrfJmJp8VPm0 u/CaEVeU4Vd/UT9dHmKuwQJdGjViwe6gsCRVZzEbgxgK15tnO+izWuooVeCc68MEG8g== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linux-foundation.org header.i=@linux-foundation.org header.a=rsa-sha256 header.s=korg header.b=Q0N9FJxi; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3DC7E606A31F; Fri, 23 Oct 2026 18:44:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key, unprotected) header.d=linux-foundation.org header.i=@linux-foundation.org header.a=rsa-sha256 header.s=korg header.b=Q0N9FJxi Received: by smtp.kernel.org (Postfix) with ESMTPSA id BE6241F01825; Fri, 23 Oct 2026 18:44:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux-foundation.org; s=korg; t=1792781046; bh=sxJRzimCkfr7PoRzvdbf9zo+BJKYvlRk+qSTPyzrglc=; h=Date:To:From:Subject; b=Q0N9FJxivOIL8dH7G2pkUMtyh1nVVbvX7c8txhxm/FvV8PSPlvNHRff5wPtabn24q mfhNpd4SjjRH0aidEsAvVlsH3gfCu1e/hf+lv+9wflrxUxTZUzb7+2T9vvJn0+HSzt zUj1+hwLOvq6X9lVOuNhtK/j2qeYD1ZPMrH0oxwc= Date: Fri, 23 Oct 2026 11:44:06 -0700 To: mm-commits@vger.kernel.org,vbabka@kernel.org,surenb@google.com,stable@vger.kernel.org,sj@kernel.org,rppt@kernel.org,pfalcato@suse.de,mhocko@suse.com,liam@infradead.org,kees@kernel.org,jannh@google.com,david@kernel.org,dave@stgolabs.net,ccross@google.com,ljs@kernel.org,akpm@linux-foundation.org From: Andrew Morton Subject: + mm-vma-avoid-losing-atomic-vma-flags-when-setting-sticky-vma-flags.patch added to mm-unstable branch Message-Id: <20261023184406.BE6241F01825@smtp.kernel.org> X-Mailing-List: mm-commits@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list The patch titled Subject: mm/vma: avoid losing atomic VMA flags when setting sticky VMA flags has been added to the -mm mm-unstable branch. Its filename is mm-vma-avoid-losing-atomic-vma-flags-when-setting-sticky-vma-flags.patch This patch will shortly appear at https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/mm-vma-avoid-losing-atomic-vma-flags-when-setting-sticky-vma-flags.patch This patch will later appear in the mm-unstable branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next via various branches at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm and is updated there most days ------------------------------------------------------ From: "Lorenzo Stoakes (ARM)" Subject: mm/vma: avoid losing atomic VMA flags when setting sticky VMA flags Date: Fri, 23 Oct 2026 14:47:30 +0100 vma_merge_existing_range() merges an existing VMA (middle) when its attributes have changed to match those of one or both adjacent VMAs. Sticky flags are propagated if they are set in any of the merged VMAs. They are initialised from vmg->vma_flags, which is assumed to contain middle's sticky flags when the function is invoked. However, the VMA write lock is not held for middle when they are first populated, so concurrent updates to atomic VMA flags may occur, which will be lost upon merge. This can result in fork failing to propagate guard region markers and (if file-backed) THP collapse discarding them. Resolve this by propagating the sticky flags after middle is locked. Make life easier by factoring this into propagate_sticky_flags(), which treats vmg->vma_flags as its base (in case any sticky flags are set there), updating it as sticky flags are accumulated from merged VMAs. Also update vma_expand() to use propagate_sticky_flags() so all merge paths utilise it. propagate_sticky_flags() also asserts that the VMA write lock is held for the VMA whose sticky flags are being read, with a comment explaining why. Another means by which atomic VMA flags can fail to be observed is when the merge is finalised in commit_merge(). rmap locks are dropped in vma_complete() before the sticky flags are written, meaning an rmap walker can observe the VMA without sticky flags set, which can also result in retract_page_tables() discarding guard markers. Resolve this by assigning the sticky flags before dropping rmap locks, factored into commit_sticky_flags() with a write assert on the VMA being written to. Also remove the vma_set_flags_mask() invocation at the end of vma_merge_existing_range() as this was introduced by commit 64212ba02e66 ("mm: implement sticky VMA flags") to propagate sticky flags, which is now redundant with the introduction of commit_sticky_flags(). The vma_set_flags_mask() invocation at the end of vma_expand() setting sticky flags only is also removed for the same reason. Also update vma_merge_existing_range()'s comment to reflect the fact that vmg->vma_flags gets updated. Finally, update the userland VMA tests to reflect a previously missed const-ification in vma_assert_write_locked() which would otherwise cause a warning when building them. Link: https://lore.kernel.org/20261023-fix-vma-atomic-v1-4-8ff4fae1fc85@kernel.org Fixes: 2ab7f1bbafc9 ("mm/madvise: allow guard page install/remove under VMA lock") Fixes: 49e14dabed7a ("mm: set the VM_MAYBE_GUARD flag on guard region install") Signed-off-by: Lorenzo Stoakes (ARM) Signed-off-by: Andrew Morton Suggested-by: David Hildenbrand (Arm) Cc: Liam R. Howlett Cc: Vlastimil Babka Cc: Mike Rapoport Cc: Suren Baghdasaryan Cc: Michal Hocko Cc: Jann Horn Cc: Pedro Falcato Cc: Davidlohr Bueso Cc: SJ Park Cc: Kees Cook Cc: Colin Cross Cc: --- mm/vma.c | 55 +++++++++++++++------------- tools/testing/vma/include/dup.h | 2 - tools/testing/vma/include/stubs.h | 2 - 3 files changed, 32 insertions(+), 27 deletions(-) --- a/mm/vma.c~mm-vma-avoid-losing-atomic-vma-flags-when-setting-sticky-vma-flags +++ a/mm/vma.c @@ -783,6 +783,27 @@ static void vmg_adjust_set_range(struct } } +static void propagate_sticky_flags(struct vma_merge_struct *vmg, + const struct vm_area_struct *vma) +{ + const vma_flags_t sticky = + vma_flags_and_mask(&vma->flags, VMA_STICKY_FLAGS); + + /* Write lock prevents concurrent atomic VMA flag updates. */ + vma_assert_write_locked(vma); + vma_flags_set_mask(&vmg->vma_flags, sticky); +} + +static void commit_sticky_flags(struct vma_merge_struct *vmg) +{ + const vma_flags_t sticky = + vma_flags_and_mask(&vmg->vma_flags, VMA_STICKY_FLAGS); + struct vm_area_struct *target = vmg->target; + + vma_assert_write_locked(target); + vma_set_flags_mask(target, sticky); +} + /* * Actually perform the VMA merge operation. * @@ -818,6 +839,8 @@ static int commit_merge(struct vma_merge return -ENOMEM; vma_prepare(&vp); + /* Must be made visible before vma_complete() for rmap walkers. */ + commit_sticky_flags(vmg); /* * THP pages may need to do additional splits if we increase * middle->vm_start. @@ -857,8 +880,8 @@ static bool can_merge_remove_vma(struct * merge. * * As part of this operation, if a merge occurs, the @vmg object will have its - * vma, start, end, and pgoff fields modified to execute the merge. Subsequent - * calls to this function should reset these fields. + * vma, start, end, pgoff and vma_flags fields modified to execute the merge. + * Subsequent calls to this function should reset these fields. * * Returns: The merged VMA if merge succeeds, or NULL otherwise. * @@ -872,8 +895,6 @@ static bool can_merge_remove_vma(struct static __must_check struct vm_area_struct *vma_merge_existing_range( struct vma_merge_struct *vmg) { - vma_flags_t sticky_flags = vma_flags_and_mask(&vmg->vma_flags, - VMA_STICKY_FLAGS); struct vm_area_struct *middle = vmg->middle; struct vm_area_struct *prev = vmg->prev; struct vm_area_struct *next; @@ -966,24 +987,18 @@ static __must_check struct vm_area_struc /* No matter what happens, we will be adjusting middle. */ vma_start_write(middle); + propagate_sticky_flags(vmg, middle); if (merge_right) { - vma_flags_t next_sticky; - vma_start_write(next); vmg->target = next; - next_sticky = vma_flags_and_mask(&next->flags, VMA_STICKY_FLAGS); - vma_flags_set_mask(&sticky_flags, next_sticky); + propagate_sticky_flags(vmg, next); } if (merge_left) { - vma_flags_t prev_sticky; - vma_start_write(prev); vmg->target = prev; - - prev_sticky = vma_flags_and_mask(&prev->flags, VMA_STICKY_FLAGS); - vma_flags_set_mask(&sticky_flags, prev_sticky); + propagate_sticky_flags(vmg, prev); } if (merge_both) { @@ -1054,7 +1069,6 @@ static __must_check struct vm_area_struc if (err || commit_merge(vmg)) goto abort; - vma_set_flags_mask(vmg->target, sticky_flags); khugepaged_enter_vma(vmg->target, vmg->vm_flags); vmg->state = VMA_MERGE_SUCCESS; return vmg->target; @@ -1241,16 +1255,11 @@ int vma_expand(struct vma_merge_struct * struct vm_area_struct *target = vmg->target; struct vm_area_struct *next = vmg->next; bool remove_next = false; - vma_flags_t sticky_flags = - vma_flags_and_mask(&vmg->vma_flags, VMA_STICKY_FLAGS); - vma_flags_t target_sticky; int ret = 0; mmap_assert_write_locked(vmg->mm); vma_start_write(target); - target_sticky = vma_flags_and_mask(&target->flags, VMA_STICKY_FLAGS); - if (next && target != next && vmg->end == next->vm_end) remove_next = true; @@ -1265,7 +1274,7 @@ int vma_expand(struct vma_merge_struct * VM_WARN_ON_VMG(target->vm_start < vmg->start || target->vm_end > vmg->end, vmg); - vma_flags_set_mask(&sticky_flags, target_sticky); + propagate_sticky_flags(vmg, target); /* * If we are removing the next VMA or copying from a VMA @@ -1282,18 +1291,14 @@ int vma_expand(struct vma_merge_struct * return ret; if (remove_next) { - vma_flags_t next_sticky; - vma_start_write(next); vmg->__remove_next = true; - next_sticky = vma_flags_and_mask(&next->flags, VMA_STICKY_FLAGS); - vma_flags_set_mask(&sticky_flags, next_sticky); + propagate_sticky_flags(vmg, next); } if (commit_merge(vmg)) goto nomem; - vma_set_flags_mask(target, sticky_flags); return 0; nomem: --- a/tools/testing/vma/include/dup.h~mm-vma-avoid-losing-atomic-vma-flags-when-setting-sticky-vma-flags +++ a/tools/testing/vma/include/dup.h @@ -1212,7 +1212,7 @@ static inline void vma_assert_detached(s WARN_ON_ONCE(vma_is_attached(vma)); } -static inline void vma_assert_write_locked(struct vm_area_struct *); +static inline void vma_assert_write_locked(const struct vm_area_struct *); static inline void vma_mark_attached(struct vm_area_struct *vma) { vma_assert_write_locked(vma); --- a/tools/testing/vma/include/stubs.h~mm-vma-avoid-losing-atomic-vma-flags-when-setting-sticky-vma-flags +++ a/tools/testing/vma/include/stubs.h @@ -320,7 +320,7 @@ static inline void anon_vma_lock_write(s { } -static inline void vma_assert_write_locked(struct vm_area_struct *vma) +static inline void vma_assert_write_locked(const struct vm_area_struct *vma) { } _ Patches currently in -mm which might be from ljs@kernel.org are mm-vma-fix-mmap_prepare-file-handling-remove-file_doesnt_need_get.patch mm-vma-introduce-and-use-vma_can_merge.patch mm-consistently-validate-vma-state-after-mmap-hooks.patch mm-vma-ensure-mmap_prepare-doesnt-set-actions-on-a-mergeable-vma.patch mm-make-map_kernel_pages_-internal-and-unexported.patch mm-vma-tidy-up-map-kernel-pages-enum-values.patch mm-assert-mmap-lock-held-use-new-flags-api-in-vm_insert_page.patch mm-add-mmap-action-for-discontiguous-kernel-page-mapping.patch docs-filesystems-update-mmap_prepare-docs-for-discontig-kernel-pgs.patch drivers-usb-mon-update-to-use-mmap_prepare-map-kernel-pages.patch infiniband-update-hfi1-to-use-remap_vmalloc_range.patch selinux-reject-writable-opens-of-policy-file-drop-mmap-shared-write-check.patch alsa-pcm-use-vm_insert_page-to-map-pcm-status-page.patch bpf-arena-mark-arena_map_mmap-mappings-vm_mixedmap.patch mm-vma-add-vma_is_mm_managed-predicates.patch mm-vma-only-allow-mmap-to-clear-vma_maywrite_bit-if-not-mm-managed.patch mm-vma-add-and-use-vma__is_fixed_mapping.patch scsi-sg-convert-mmap-hook-to-mmap_prepare-and-rework.patch fbdev-defio-assert-fbinfo_virtfb-drop-vm_io-add-vm_mixedmap.patch hsi-cmt_speech-convert-mmap-hook-to-mmap_prepare-refactor.patch mm-gup-error-out-early-on-vma_mayread_bit-vmas.patch uprobes-remove-vm_io-set-vm_mixedmap-for-mapped-kernel-pages.patch mm-mlock-clear-vma_locked_mask-over-mmap-callback.patch mm-mlock-eliminate-weird-vma_io_bit-abuse-and-simplify.patch mm-vma-enforce-that-mm-managed-mappings-may-not-set-vma_io_bit.patch mm-remove-vma_io_bit-check-in-vma_is_mm_managed.patch mm-remove-hugetlb_inlineh.patch mm-rename-is_vm_hugetlb_page-to-vma_is_hugetlb.patch mm-drop-some-redundant-checks-around-hugetlb-vmas.patch mm-vma-introduce-vma_is_mm_backed.patch mm-madvise-update-is_valid_guard_vma-to-use-vma_is_mm_backed.patch mm-uffd-use-predicates-for-userfaultfd-checks.patch mm-madvise-use-predicates-for-madvise-madv_dofork.patch mm-eliminate-vma_special_flags-usage-when-hugetlb-explicitly-tested.patch mm-eliminate-vma_special_flags-check-in-lru_gen_look_around.patch mm-avoid-use-of-vma_special_flags-in-migrate_vma_setup.patch mm-eliminate-vm_special-vma_special_flags.patch fuse-dax-do-not-set-vm_mixedmap.patch mm-huge_memory-remove-vma_is_special_huge.patch mm-vma-const-ify-vma_assert_stabilised-and-associated-functions.patch mm-implement-and-use-vma_has_anon_rmap-silence-kcsan.patch mm-update-comments-to-refer-to-anon-rmap-rather-than-anon_vma.patch mm-vma-dont-remove-vma-from-rmap-if-pgoff-unchanged.patch mm-vma-avoid-spurious-write-locks-when-mm-mm_lock_seq-overflows.patch mm-mremap-populate-calculated-fields-in-vrm-state-correctly.patch mm-mremap-correctly-uncharge-accountable-vmas-in-error-path.patch mm-vma-avoid-broken-uffd-merge-on-mremap.patch mm-vma-fix-expansion-of-vma_mixedmap_bit-vmas.patch mm-do-not-unintentionally-overwrite-atomic-vma-flags.patch mm-vma-avoid-losing-atomic-vma-flags-when-setting-sticky-vma-flags.patch