On Thu, Nov 16, 2023 at 12:15 PM Peter Xu <peterx@xxxxxxxxxx> wrote: > > The new ioctl(PAGEMAP_SCAN) relies on vma wr-protect capability provided by > userfault, however in the vma test it didn't explicitly require the vma to > have wr-protect function enabled, even if PM_SCAN_WP_MATCHING flag is set. > > It means the pagemap code can now apply uffd-wp bit to a page in the vma > even if not registered to userfaultfd at all. > > Then in whatever way as long as the pte got written and page fault > resolved, we'll apply the write bit even if uffd-wp bit is set. We'll see > a pte that has both UFFD_WP and WRITE bit set. Anything later that looks > up the pte for uffd-wp bit will trigger the warning: > > WARNING: CPU: 1 PID: 5071 at arch/x86/include/asm/pgtable.h:403 pte_uffd_wp arch/x86/include/asm/pgtable.h:403 [inline] > > Fix it by doing proper check over the vma attributes when > PM_SCAN_WP_MATCHING is specified. > > Fixes: 52526ca7fdb9 ("fs/proc/task_mmu: implement IOCTL to get and optionally clear info about PTEs") > Reported-by: syzbot+e94c5aaf7890901ebf9b@xxxxxxxxxxxxxxxxxxxxxxxxx > Signed-off-by: Peter Xu <peterx@xxxxxxxxxx> Reviewed-by: Andrei Vagin <avagin@xxxxxxxxx> > --- > fs/proc/task_mmu.c | 24 ++++++++++++++++++++---- > 1 file changed, 20 insertions(+), 4 deletions(-) > > diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c > index 51e0ec658457..e91085d79926 100644 > --- a/fs/proc/task_mmu.c > +++ b/fs/proc/task_mmu.c > @@ -1994,15 +1994,31 @@ static int pagemap_scan_test_walk(unsigned long start, unsigned long end, > struct pagemap_scan_private *p = walk->private; > struct vm_area_struct *vma = walk->vma; > unsigned long vma_category = 0; > + bool wp_allowed = userfaultfd_wp_async(vma) && > + userfaultfd_wp_use_markers(vma); > > - if (userfaultfd_wp_async(vma) && userfaultfd_wp_use_markers(vma)) > - vma_category |= PAGE_IS_WPALLOWED; > - else if (p->arg.flags & PM_SCAN_CHECK_WPASYNC) > - return -EPERM; > + if (!wp_allowed) { > + /* User requested explicit failure over wp-async capability */ > + if (p->arg.flags & PM_SCAN_CHECK_WPASYNC) > + return -EPERM; > + /* > + * User requires wr-protect, and allows silently skipping > + * unsupported vmas. > + */ > + if (p->arg.flags & PM_SCAN_WP_MATCHING) > + return 1; > + /* > + * Then the request doesn't involve wr-protects at all, > + * fall through to the rest checks, and allow vma walk. > + */ > + } > > if (vma->vm_flags & VM_PFNMAP) > return 1; > > + if (wp_allowed) > + vma_category |= PAGE_IS_WPALLOWED; > + > if (vma->vm_flags & VM_SOFTDIRTY) > vma_category |= PAGE_IS_SOFT_DIRTY; > > -- > 2.41.0 >