powerpc/mm: Add proper pte access check helper for other platforms
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Mon, 4 Dec 2017 02:19:12 +0000 (07:49 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Fri, 22 Dec 2017 11:28:40 +0000 (22:28 +1100)
pte_access_premitted get called in get_user_pages_fast path. If we
have marked the pte PROT_NONE, we should not allow a read access on
the address. With the current implementation we are not checking the
READ and only check for WRITE. This is needed on archs like ppc64 that
implement PROT_NONE using _PAGE_USER access instead of _PAGE_PRESENT.
Also add pte_user check just to make sure we are not accessing kernel
mapping.

Even though there is code duplication, keeping the low level pte
accessors different for different platforms helps in code readability.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/book3s/32/pgtable.h
arch/powerpc/include/asm/nohash/pgtable.h

index 016579ef16d3d411a4e4caa36bccbd5f7ad8e5c5..30a155c0a6b07e31ca69d5a7418fb19a1f6e7872 100644 (file)
@@ -311,6 +311,29 @@ static inline int pte_present(pte_t pte)
        return pte_val(pte) & _PAGE_PRESENT;
 }
 
+/*
+ * We only find page table entry in the last level
+ * Hence no need for other accessors
+ */
+#define pte_access_permitted pte_access_permitted
+static inline bool pte_access_permitted(pte_t pte, bool write)
+{
+       unsigned long pteval = pte_val(pte);
+       /*
+        * A read-only access is controlled by _PAGE_USER bit.
+        * We have _PAGE_READ set for WRITE and EXECUTE
+        */
+       unsigned long need_pte_bits = _PAGE_PRESENT | _PAGE_USER;
+
+       if (write)
+               need_pte_bits |= _PAGE_WRITE;
+
+       if ((pteval & need_pte_bits) != need_pte_bits)
+               return false;
+
+       return true;
+}
+
 /* Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  *
index 5c68f4a59f75802d3ff98b43b951480b525daee7..fc4376c8d4446a6231bbd92e5a366daccc378528 100644 (file)
@@ -45,6 +45,29 @@ static inline int pte_present(pte_t pte)
        return pte_val(pte) & _PAGE_PRESENT;
 }
 
+/*
+ * We only find page table entry in the last level
+ * Hence no need for other accessors
+ */
+#define pte_access_permitted pte_access_permitted
+static inline bool pte_access_permitted(pte_t pte, bool write)
+{
+       unsigned long pteval = pte_val(pte);
+       /*
+        * A read-only access is controlled by _PAGE_USER bit.
+        * We have _PAGE_READ set for WRITE and EXECUTE
+        */
+       unsigned long need_pte_bits = _PAGE_PRESENT | _PAGE_USER;
+
+       if (write)
+               need_pte_bits |= _PAGE_WRITE;
+
+       if ((pteval & need_pte_bits) != need_pte_bits)
+               return false;
+
+       return true;
+}
+
 /* Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  *