Re: [PATCH RFC v4 04/12] mm/gup: let check_vma_flags() ignore selected VMA flags

From: John Hubbard

Date: Mon Jul 27 2026 - 22:41:03 EST


On 7/24/26 3:29 PM, Rik van Riel wrote:
> check_vma_flags() rejects a VMA whose flags gup cannot handle. A caller
> that wants to reach a COWed page in a VM_IO or VM_PFNMAP VMA, where that
> page does have a struct page, cannot express the exception and has to
> repeat the flag test itself.
>
> Add an ignore_flags argument that check_vma_flags() clears from its local
> copy of vma->vm_flags before the flag checks. A caller can drop a single
> rejection this way while keeping every other check. All current callers
> pass 0.
>
> This prepares for get_user_page_vma(), which passes VM_IO | VM_PFNMAP to
> reach those COWed pages.
>
> No functional change intended.
>
> Assisted-by: Claude:claude-opus-4.8
> Signed-off-by: Rik van Riel <riel@xxxxxxxxxxx>
> ---
> mm/gup.c | 14 +++++++++++---
> 1 file changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/mm/gup.c b/mm/gup.c
> index 0692119b7904..dcece7b5253c 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -1197,13 +1197,21 @@ static bool writable_file_mapping_allowed(struct vm_area_struct *vma,
> return !vma_needs_dirty_tracking(vma);
> }
>
> -static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)
> +static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags,
> + vm_flags_t ignore_flags)

All callers pass zero in this patch, so there is no behavior change yet.
The problem is the interface being added.

The same local vm_flags value is used for the VM_IO/VM_PFNMAP gate,
VM_WRITE, VM_SHADOW_STACK, VM_READ, VM_MAYREAD, and is_cow_mapping().

An arbitrary mask can therefore alter permission, shadow-stack, and COW
validation. For example, masking VM_SHARED changes the result of
is_cow_mapping(), while masking VM_SHADOW_STACK removes its write
rejection. Checks implemented through helpers still read the original
vma->vm_flags, so the meaning of ignore_flags also depends on how each
check happens to be implemented.

Perhaps it is best to replace the mask with a single-purpose internal
GUP flag, such as FOLL_PFNMAP_COW, and apply it only to the
special-mapping gate:

if (vm_flags & (VM_IO | VM_PFNMAP) &&
(!(gup_flags & FOLL_PFNMAP_COW) ||
!(vm_flags & VM_PFNMAP)))
return -EFAULT;

This permits the later caller to examine a VM_PFNMAP mapping while
keeping VM_IO-only mappings and every other VMA check unchanged.



thanks,
--
John Hubbard