No functional change in this patch. This update gup_hugepte to use the
helper. This will help later when we add memory keys.
Signed-off-by: Aneesh Kumar K.V <redacted>
---
arch/powerpc/mm/hugetlbpage.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
@@ -855,9 +855,7 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,pte=READ_ONCE(*ptep);-if(!pte_present(pte)||!pte_read(pte))-return0;-if(write&&!pte_write(pte))+if(!pte_access_permitted(pte,write))return0;/* hugepages are never "special" */
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
RWX access instead of _PAGE_PRESENT. Also add pte_user check just to make sure
we are not accessing kernel mapping.
Signed-off-by: Aneesh Kumar K.V <redacted>
---
arch/powerpc/include/asm/book3s/64/pgtable.h | 41 ++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
@@ -863,6 +892,12 @@ static inline int pgd_bad(pgd_t pgd)returnhash__pgd_bad(pgd);}+#define pgd_access_permitted pgd_access_permitted+staticinlineboolpgd_access_permitted(pgd_tpgd,boolwrite)+{+returnpte_access_permitted(pgd_pte(pgd),write);+}+externstructpage*pgd_page(pgd_tpgd);/* Pointers in the page table tree are physical addresses */
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 <redacted>
---
arch/powerpc/include/asm/book3s/32/pgtable.h | 23 +++++++++++++++++++++++
arch/powerpc/include/asm/nohash/pgtable.h | 23 +++++++++++++++++++++++
2 files changed, 46 insertions(+)
@@ -311,6 +311,29 @@ static inline int pte_present(pte_t pte)returnpte_val(pte)&_PAGE_PRESENT;}+/*+*Weonlyfindpagetableentryinthelastlevel+*Hencenoneedforotheraccessors+*/+#define pte_access_permitted pte_access_permitted+staticinlineboolpte_access_permitted(pte_tpte,boolwrite)+{+unsignedlongpteval=pte_val(pte);+/*+*Aread-onlyaccessiscontrolledby_PAGE_USERbit.+*Wehave_PAGE_READsetforWRITEandEXECUTE+*/+unsignedlongneed_pte_bits=_PAGE_PRESENT|_PAGE_USER;++if(write)+need_pte_bits|=_PAGE_WRITE;++if((pteval&need_pte_bits)!=need_pte_bits)+returnfalse;++returntrue;+}+/* Conversion functions: convert a page and protection to a page entry,*andapageentryandpagedirectorytothepagetheyreferto.*
@@ -45,6 +45,29 @@ static inline int pte_present(pte_t pte)returnpte_val(pte)&_PAGE_PRESENT;}+/*+*Weonlyfindpagetableentryinthelastlevel+*Hencenoneedforotheraccessors+*/+#define pte_access_permitted pte_access_permitted+staticinlineboolpte_access_permitted(pte_tpte,boolwrite)+{+unsignedlongpteval=pte_val(pte);+/*+*Aread-onlyaccessiscontrolledby_PAGE_USERbit.+*Wehave_PAGE_READsetforWRITEandEXECUTE+*/+unsignedlongneed_pte_bits=_PAGE_PRESENT|_PAGE_USER;++if(write)+need_pte_bits|=_PAGE_WRITE;++if((pteval&need_pte_bits)!=need_pte_bits)+returnfalse;++returntrue;+}+/* Conversion functions: convert a page and protection to a page entry,*andapageentryandpagedirectorytothepagetheyreferto.*
From: Michael Ellerman <hidden> Date: 2018-01-17 13:30:09
On Mon, 2017-12-04 at 02:19:10 UTC, "Aneesh Kumar K.V" wrote:
No functional change in this patch. This update gup_hugepte to use the
helper. This will help later when we add memory keys.
Signed-off-by: Aneesh Kumar K.V <redacted>
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 <redacted>
---
arch/powerpc/include/asm/book3s/32/pgtable.h | 23 +++++++++++++++++++++++
arch/powerpc/include/asm/nohash/pgtable.h | 23 +++++++++++++++++++++++
2 files changed, 46 insertions(+)
@@ -311,6 +311,29 @@ static inline int pte_present(pte_t pte)returnpte_val(pte)&_PAGE_PRESENT;}+/*+*Weonlyfindpagetableentryinthelastlevel+*Hencenoneedforotheraccessors+*/+#define pte_access_permitted pte_access_permitted+staticinlineboolpte_access_permitted(pte_tpte,boolwrite)+{+unsignedlongpteval=pte_val(pte);+/*+*Aread-onlyaccessiscontrolledby_PAGE_USERbit.+*Wehave_PAGE_READsetforWRITEandEXECUTE+*/+unsignedlongneed_pte_bits=_PAGE_PRESENT|_PAGE_USER;++if(write)+need_pte_bits|=_PAGE_WRITE;++if((pteval&need_pte_bits)!=need_pte_bits)+returnfalse;++returntrue;+}+/* Conversion functions: convert a page and protection to a page entry,*andapageentryandpagedirectorytothepagetheyreferto.*
+ 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;
This test is not fully correct:
- To check access(read) permission, you also have to check that _PAGE_NA
is not set.
- To check write permission, you also have to check that neither
_PAGE_NA nor _PAGE_RO are set.
On the 8xx, you have:
_PAGE_RW = _PAGE_WRITE = 0
_PAGE_NA = 0x0200
_PAGE_RO = 0x0600
Christophe
+
+ 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.
*
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 <redacted>
---
arch/powerpc/include/asm/book3s/32/pgtable.h | 23
+++++++++++++++++++++++
arch/powerpc/include/asm/nohash/pgtable.h | 23
+++++++++++++++++++++++
2 files changed, 46 insertions(+)
@@ -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.
*
@@ -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;
_PAGE_PRIVILEGED should be checked as well.
Indeed, it seems like our patches crossed each other. My patch for
adding _PAGE_PRIVILEGED is date January 16th while your's was merged on
the 17th.
I'm wondering if there are other places that are missing _PAGE_RO
handling and _PAGE_PRIVILEGED handling. Do you remember if you added any
recently ?
Christophe
quoted
+
+ if (write)
+ need_pte_bits |= _PAGE_WRITE;
+
+ if ((pteval & need_pte_bits) != need_pte_bits)
+ return false;
This test is not fully correct:
- To check access(read) permission, you also have to check that _PAGE_NA
is not set.
- To check write permission, you also have to check that neither
_PAGE_NA nor _PAGE_RO are set.
On the 8xx, you have:
_PAGE_RW = _PAGE_WRITE = 0
_PAGE_NA = 0x0200
_PAGE_RO = 0x0600
Christophe
quoted
+
+ 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.
*
No functional change in this patch. This update gup_hugepte to use the
helper. This will help later when we add memory keys.
Signed-off-by: Aneesh Kumar K.V <redacted>
---
arch/powerpc/mm/hugetlbpage.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
@@ -855,9 +855,7 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,pte=READ_ONCE(*ptep);-if(!pte_present(pte)||!pte_read(pte))-return0;-if(write&&!pte_write(pte))+if(!pte_access_permitted(pte,write))
Seems like pte_access_permitted() doesn't check _PAGE_RO whereas
pte_write() does.
Christophe