mm/userfaultfd: UFFDIO_MOVE implementation should use ptep_get()
authorRyan Roberts <ryan.roberts@arm.com>
Tue, 23 Jan 2024 14:17:55 +0000 (14:17 +0000)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 8 Feb 2024 05:20:33 +0000 (21:20 -0800)
Commit c33c794828f2 ("mm: ptep_get() conversion") converted all (non-arch)
call sites to use ptep_get() instead of doing a direct dereference of the
pte.  Full rationale can be found in that commit's log.

Since then, UFFDIO_MOVE has been implemented which does 7 direct pte
dereferences.  Let's fix those up to use ptep_get().

I've asserted in the past that there is no reliable automated mechanism to
catch these; I'm relying on a combination of Coccinelle (which throws up a
lot of false positives) and some compiler magic to force a compiler error
on dereference.  But given the frequency with which new issues are coming
up, I'll add it to my todo list to try to find an automated solution.

Link: https://lkml.kernel.org/r/20240123141755.3836179-1-ryan.roberts@arm.com
Fixes: adef440691ba ("userfaultfd: UFFDIO_MOVE uABI")
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: David Hildenbrand <david@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/userfaultfd.c

index 75fcf1f783bc567d1a916c85fb7abddc169f7fb5..7cf7d43842590ccd99bf37795918a7054b61a8c4 100644 (file)
@@ -902,8 +902,8 @@ static int move_present_pte(struct mm_struct *mm,
 
        double_pt_lock(dst_ptl, src_ptl);
 
-       if (!pte_same(*src_pte, orig_src_pte) ||
-           !pte_same(*dst_pte, orig_dst_pte)) {
+       if (!pte_same(ptep_get(src_pte), orig_src_pte) ||
+           !pte_same(ptep_get(dst_pte), orig_dst_pte)) {
                err = -EAGAIN;
                goto out;
        }
@@ -946,8 +946,8 @@ static int move_swap_pte(struct mm_struct *mm,
 
        double_pt_lock(dst_ptl, src_ptl);
 
-       if (!pte_same(*src_pte, orig_src_pte) ||
-           !pte_same(*dst_pte, orig_dst_pte)) {
+       if (!pte_same(ptep_get(src_pte), orig_src_pte) ||
+           !pte_same(ptep_get(dst_pte), orig_dst_pte)) {
                double_pt_unlock(dst_ptl, src_ptl);
                return -EAGAIN;
        }
@@ -1016,7 +1016,7 @@ retry:
        }
 
        spin_lock(dst_ptl);
-       orig_dst_pte = *dst_pte;
+       orig_dst_pte = ptep_get(dst_pte);
        spin_unlock(dst_ptl);
        if (!pte_none(orig_dst_pte)) {
                err = -EEXIST;
@@ -1024,7 +1024,7 @@ retry:
        }
 
        spin_lock(src_ptl);
-       orig_src_pte = *src_pte;
+       orig_src_pte = ptep_get(src_pte);
        spin_unlock(src_ptl);
        if (pte_none(orig_src_pte)) {
                if (!(mode & UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES))
@@ -1054,7 +1054,7 @@ retry:
                         * page isn't freed under us
                         */
                        spin_lock(src_ptl);
-                       if (!pte_same(orig_src_pte, *src_pte)) {
+                       if (!pte_same(orig_src_pte, ptep_get(src_pte))) {
                                spin_unlock(src_ptl);
                                err = -EAGAIN;
                                goto out;