Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Revert "mm: replace p??_write with pte_access_permitted in fault + gup paths"

This reverts commits 5c9d2d5c269c, c7da82b894e9, and e7fe7b5cae90.

We'll probably need to revisit this, but basically we should not
complicate the get_user_pages_fast() case, and checking the actual page
table protection key bits will require more care anyway, since the
protection keys depend on the exact state of the VM in question.

Particularly when doing a "remote" page lookup (ie in somebody elses VM,
not your own), you need to be much more careful than this was. Dave
Hansen says:

"So, the underlying bug here is that we now a get_user_pages_remote()
and then go ahead and do the p*_access_permitted() checks against the
current PKRU. This was introduced recently with the addition of the
new p??_access_permitted() calls.

We have checks in the VMA path for the "remote" gups and we avoid
consulting PKRU for them. This got missed in the pkeys selftests
because I did a ptrace read, but not a *write*. I also didn't
explicitly test it against something where a COW needed to be done"

It's also not entirely clear that it makes sense to check the protection
key bits at this level at all. But one possible eventual solution is to
make the get_user_pages_fast() case just abort if it sees protection key
bits set, which makes us fall back to the regular get_user_pages() case,
which then has a vma and can do the check there if we want to.

We'll see.

Somewhat related to this all: what we _do_ want to do some day is to
check the PAGE_USER bit - it should obviously always be set for user
pages, but it would be a good check to have back. Because we have no
generic way to test for it, we lost it as part of moving over from the
architecture-specific x86 GUP implementation to the generic one in
commit e585513b76f7 ("x86/mm/gup: Switch GUP to the generic
get_user_page_fast() implementation").

Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: "Jérôme Glisse" <jglisse@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

+15 -22
-6
arch/s390/include/asm/pgtable.h
··· 1264 1264 return pud; 1265 1265 } 1266 1266 1267 - #define pud_write pud_write 1268 - static inline int pud_write(pud_t pud) 1269 - { 1270 - return (pud_val(pud) & _REGION3_ENTRY_WRITE) != 0; 1271 - } 1272 - 1273 1267 static inline pud_t pud_mkclean(pud_t pud) 1274 1268 { 1275 1269 if (pud_large(pud)) {
+2 -2
arch/sparc/mm/gup.c
··· 75 75 if (!(pmd_val(pmd) & _PAGE_VALID)) 76 76 return 0; 77 77 78 - if (!pmd_access_permitted(pmd, write)) 78 + if (write && !pmd_write(pmd)) 79 79 return 0; 80 80 81 81 refs = 0; ··· 114 114 if (!(pud_val(pud) & _PAGE_VALID)) 115 115 return 0; 116 116 117 - if (!pud_access_permitted(pud, write)) 117 + if (write && !pud_write(pud)) 118 118 return 0; 119 119 120 120 refs = 0;
+1 -2
fs/dax.c
··· 627 627 628 628 if (pfn != pmd_pfn(*pmdp)) 629 629 goto unlock_pmd; 630 - if (!pmd_dirty(*pmdp) 631 - && !pmd_access_permitted(*pmdp, WRITE)) 630 + if (!pmd_dirty(*pmdp) && !pmd_write(*pmdp)) 632 631 goto unlock_pmd; 633 632 634 633 flush_cache_page(vma, address, pfn);
+1 -1
mm/gup.c
··· 66 66 */ 67 67 static inline bool can_follow_write_pte(pte_t pte, unsigned int flags) 68 68 { 69 - return pte_access_permitted(pte, WRITE) || 69 + return pte_write(pte) || 70 70 ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte)); 71 71 } 72 72
+4 -4
mm/hmm.c
··· 391 391 if (pmd_protnone(pmd)) 392 392 return hmm_vma_walk_clear(start, end, walk); 393 393 394 - if (!pmd_access_permitted(pmd, write_fault)) 394 + if (write_fault && !pmd_write(pmd)) 395 395 return hmm_vma_walk_clear(start, end, walk); 396 396 397 397 pfn = pmd_pfn(pmd) + pte_index(addr); 398 - flag |= pmd_access_permitted(pmd, WRITE) ? HMM_PFN_WRITE : 0; 398 + flag |= pmd_write(pmd) ? HMM_PFN_WRITE : 0; 399 399 for (; addr < end; addr += PAGE_SIZE, i++, pfn++) 400 400 pfns[i] = hmm_pfn_t_from_pfn(pfn) | flag; 401 401 return 0; ··· 456 456 continue; 457 457 } 458 458 459 - if (!pte_access_permitted(pte, write_fault)) 459 + if (write_fault && !pte_write(pte)) 460 460 goto fault; 461 461 462 462 pfns[i] = hmm_pfn_t_from_pfn(pte_pfn(pte)) | flag; 463 - pfns[i] |= pte_access_permitted(pte, WRITE) ? HMM_PFN_WRITE : 0; 463 + pfns[i] |= pte_write(pte) ? HMM_PFN_WRITE : 0; 464 464 continue; 465 465 466 466 fault:
+3 -3
mm/huge_memory.c
··· 870 870 */ 871 871 WARN_ONCE(flags & FOLL_COW, "mm: In follow_devmap_pmd with FOLL_COW set"); 872 872 873 - if (!pmd_access_permitted(*pmd, flags & FOLL_WRITE)) 873 + if (flags & FOLL_WRITE && !pmd_write(*pmd)) 874 874 return NULL; 875 875 876 876 if (pmd_present(*pmd) && pmd_devmap(*pmd)) ··· 1012 1012 1013 1013 assert_spin_locked(pud_lockptr(mm, pud)); 1014 1014 1015 - if (!pud_access_permitted(*pud, flags & FOLL_WRITE)) 1015 + if (flags & FOLL_WRITE && !pud_write(*pud)) 1016 1016 return NULL; 1017 1017 1018 1018 if (pud_present(*pud) && pud_devmap(*pud)) ··· 1386 1386 */ 1387 1387 static inline bool can_follow_write_pmd(pmd_t pmd, unsigned int flags) 1388 1388 { 1389 - return pmd_access_permitted(pmd, WRITE) || 1389 + return pmd_write(pmd) || 1390 1390 ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pmd_dirty(pmd)); 1391 1391 } 1392 1392
+4 -4
mm/memory.c
··· 3949 3949 if (unlikely(!pte_same(*vmf->pte, entry))) 3950 3950 goto unlock; 3951 3951 if (vmf->flags & FAULT_FLAG_WRITE) { 3952 - if (!pte_access_permitted(entry, WRITE)) 3952 + if (!pte_write(entry)) 3953 3953 return do_wp_page(vmf); 3954 3954 entry = pte_mkdirty(entry); 3955 3955 } ··· 4014 4014 4015 4015 /* NUMA case for anonymous PUDs would go here */ 4016 4016 4017 - if (dirty && !pud_access_permitted(orig_pud, WRITE)) { 4017 + if (dirty && !pud_write(orig_pud)) { 4018 4018 ret = wp_huge_pud(&vmf, orig_pud); 4019 4019 if (!(ret & VM_FAULT_FALLBACK)) 4020 4020 return ret; ··· 4047 4047 if (pmd_protnone(orig_pmd) && vma_is_accessible(vma)) 4048 4048 return do_huge_pmd_numa_page(&vmf, orig_pmd); 4049 4049 4050 - if (dirty && !pmd_access_permitted(orig_pmd, WRITE)) { 4050 + if (dirty && !pmd_write(orig_pmd)) { 4051 4051 ret = wp_huge_pmd(&vmf, orig_pmd); 4052 4052 if (!(ret & VM_FAULT_FALLBACK)) 4053 4053 return ret; ··· 4337 4337 goto out; 4338 4338 pte = *ptep; 4339 4339 4340 - if (!pte_access_permitted(pte, flags & FOLL_WRITE)) 4340 + if ((flags & FOLL_WRITE) && !pte_write(pte)) 4341 4341 goto unlock; 4342 4342 4343 4343 *prot = pgprot_val(pte_pgprot(pte));