Introduce PAGE_NONE_X macro which provides exec-only rights.

For the time being, this is a copy of PAGE_READONLY_X on all subarches
except on book3s/64 where PAGE_EXECONLY becomes PAGE_NONE_X.

On book3s/64, as PAGE_EXECONLY is only valid for Radix add
VM_READ flag in vm_get_page_prot() for non-Radix.

And update access_error() so that a non exec fault on a VM_EXEC only
mapping is always invalid, even when the underlying layer don't
always generate a fault for that.

Signed-off-by: Christophe Leroy <christophe.le...@csgroup.eu>
Cc: Russell Currey <rus...@russell.cc>
Cc: Kees Cook <keesc...@chromium.org>
---
 arch/powerpc/include/asm/book3s/32/pgtable.h  |  1 +
 arch/powerpc/include/asm/book3s/64/pgtable.h  |  4 ++--
 arch/powerpc/include/asm/nohash/32/pte-40x.h  |  1 +
 arch/powerpc/include/asm/nohash/32/pte-44x.h  |  1 +
 arch/powerpc/include/asm/nohash/32/pte-85xx.h |  1 +
 arch/powerpc/include/asm/nohash/32/pte-8xx.h  |  1 +
 arch/powerpc/include/asm/nohash/pte-e500.h    |  1 +
 arch/powerpc/mm/book3s64/pgtable.c            | 10 ++++------
 arch/powerpc/mm/fault.c                       |  9 +++++----
 arch/powerpc/mm/pgtable.c                     |  4 ++--
 10 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h 
b/arch/powerpc/include/asm/book3s/32/pgtable.h
index d49c2a9d4ffe..96a38ce29a76 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -105,6 +105,7 @@ static inline bool pte_user(pte_t pte)
  * Write permissions imply read permissions for now.
  */
 #define PAGE_NONE      __pgprot(_PAGE_BASE)
+#define PAGE_NONE_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
 #define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
 #define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | 
_PAGE_EXEC)
 #define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER)
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h 
b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 4acc9690f599..4ae909e95d46 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -144,14 +144,14 @@
  * possible on platforms that define _PAGE_EXEC
  */
 #define PAGE_NONE      __pgprot(_PAGE_BASE | _PAGE_PRIVILEGED)
+/* Radix only, Hash uses PAGE_READONLY_X + execute-only pkey instead */
+#define PAGE_NONE_X    __pgprot(_PAGE_BASE | _PAGE_EXEC)
 #define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_RW)
 #define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_EXEC)
 #define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_READ)
 #define PAGE_COPY_X    __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC)
 #define PAGE_READONLY  __pgprot(_PAGE_BASE | _PAGE_READ)
 #define PAGE_READONLY_X        __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC)
-/* Radix only, Hash uses PAGE_READONLY_X + execute-only pkey instead */
-#define PAGE_EXECONLY  __pgprot(_PAGE_BASE | _PAGE_EXEC)
 
 /* Permission masks used for kernel mappings */
 #define PAGE_KERNEL    __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW)
diff --git a/arch/powerpc/include/asm/nohash/32/pte-40x.h 
b/arch/powerpc/include/asm/nohash/32/pte-40x.h
index 6fe46e754556..b5ad980cca64 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-40x.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-40x.h
@@ -77,6 +77,7 @@
 
 /* Permission masks used to generate the __P and __S table */
 #define PAGE_NONE      __pgprot(_PAGE_BASE)
+#define PAGE_NONE_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
 #define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
 #define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | 
_PAGE_EXEC)
 #define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER)
diff --git a/arch/powerpc/include/asm/nohash/32/pte-44x.h 
b/arch/powerpc/include/asm/nohash/32/pte-44x.h
index b7ed13cee137..afea625b6ad2 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-44x.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-44x.h
@@ -107,6 +107,7 @@
 
 /* Permission masks used to generate the __P and __S table */
 #define PAGE_NONE      __pgprot(_PAGE_BASE)
+#define PAGE_NONE_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
 #define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
 #define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | 
_PAGE_EXEC)
 #define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER)
diff --git a/arch/powerpc/include/asm/nohash/32/pte-85xx.h 
b/arch/powerpc/include/asm/nohash/32/pte-85xx.h
index 16451df5ddb0..7cfe4913f3aa 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-85xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-85xx.h
@@ -63,6 +63,7 @@
 
 /* Permission masks used to generate the __P and __S table */
 #define PAGE_NONE      __pgprot(_PAGE_BASE)
+#define PAGE_NONE_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
 #define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
 #define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | 
_PAGE_EXEC)
 #define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER)
diff --git a/arch/powerpc/include/asm/nohash/32/pte-8xx.h 
b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
index 1a89ebdc3acc..b234a93b05f1 100644
--- a/arch/powerpc/include/asm/nohash/32/pte-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/pte-8xx.h
@@ -79,6 +79,7 @@
 
 /* Permission masks used to generate the __P and __S table */
 #define PAGE_NONE      __pgprot(_PAGE_BASE | _PAGE_NA)
+#define PAGE_NONE_X    __pgprot(_PAGE_BASE | _PAGE_RO | _PAGE_EXEC)
 #define PAGE_SHARED    __pgprot(_PAGE_BASE)
 #define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_EXEC)
 #define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_RO)
diff --git a/arch/powerpc/include/asm/nohash/pte-e500.h 
b/arch/powerpc/include/asm/nohash/pte-e500.h
index d8924cbd61e4..1cd9c19b81a0 100644
--- a/arch/powerpc/include/asm/nohash/pte-e500.h
+++ b/arch/powerpc/include/asm/nohash/pte-e500.h
@@ -91,6 +91,7 @@
 
 /* Permission masks used to generate the __P and __S table */
 #define PAGE_NONE      __pgprot(_PAGE_BASE)
+#define PAGE_NONE_X    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_BAP_UX)
 #define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
 #define PAGE_SHARED_X  __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | 
_PAGE_BAP_UX)
 #define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER)
diff --git a/arch/powerpc/mm/book3s64/pgtable.c 
b/arch/powerpc/mm/book3s64/pgtable.c
index 2f2872986b09..d1d7e314c0d8 100644
--- a/arch/powerpc/mm/book3s64/pgtable.c
+++ b/arch/powerpc/mm/book3s64/pgtable.c
@@ -557,12 +557,10 @@ pgprot_t vm_get_page_prot(unsigned long vm_flags)
        unsigned long prot;
 
        /* Radix supports execute-only, but protection_map maps X -> RX */
-       if (radix_enabled() && ((vm_flags & VM_ACCESS_FLAGS) == VM_EXEC)) {
-               prot = pgprot_val(PAGE_EXECONLY);
-       } else {
-               prot = pgprot_val(protection_map[vm_flags &
-                                                (VM_ACCESS_FLAGS | 
VM_SHARED)]);
-       }
+       if (!radix_enabled() && ((vm_flags & VM_ACCESS_FLAGS) == VM_EXEC))
+               vm_flags |= VM_READ;
+
+       prot = pgprot_val(protection_map[vm_flags & (VM_ACCESS_FLAGS | 
VM_SHARED)]);
 
        if (vm_flags & VM_SAO)
                prot |= _PAGE_SAO;
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 5bfdf6ecfa96..50e1bfffe552 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -266,14 +266,15 @@ static bool access_error(bool is_write, bool is_exec, 
struct vm_area_struct *vma
        }
 
        /*
-        * VM_READ, VM_WRITE and VM_EXEC all imply read permissions, as
-        * defined in protection_map[].  Read faults can only be caused by
-        * a PROT_NONE mapping, or with a PROT_EXEC-only mapping on Radix.
+        * VM_READ, VM_WRITE and VM_EXEC may imply read permissions, as
+        * defined in protection_map[].  In that case Read faults can only be
+        * caused by a PROT_NONE mapping. However a non exec access on a
+        * VM_EXEC only mapping is invalid anyway, so report it as such.
         */
        if (unlikely(!vma_is_accessible(vma)))
                return true;
 
-       if (unlikely(radix_enabled() && ((vma->vm_flags & VM_ACCESS_FLAGS) == 
VM_EXEC)))
+       if ((vma->vm_flags & VM_ACCESS_FLAGS) == VM_EXEC)
                return true;
 
        /*
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index cb2dcdb18f8e..1a27489e235b 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -479,7 +479,7 @@ const pgprot_t protection_map[16] = {
        [VM_READ]                                       = PAGE_READONLY,
        [VM_WRITE]                                      = PAGE_COPY,
        [VM_WRITE | VM_READ]                            = PAGE_COPY,
-       [VM_EXEC]                                       = PAGE_READONLY_X,
+       [VM_EXEC]                                       = PAGE_NONE_X,
        [VM_EXEC | VM_READ]                             = PAGE_READONLY_X,
        [VM_EXEC | VM_WRITE]                            = PAGE_COPY_X,
        [VM_EXEC | VM_WRITE | VM_READ]                  = PAGE_COPY_X,
@@ -487,7 +487,7 @@ const pgprot_t protection_map[16] = {
        [VM_SHARED | VM_READ]                           = PAGE_READONLY,
        [VM_SHARED | VM_WRITE]                          = PAGE_SHARED,
        [VM_SHARED | VM_WRITE | VM_READ]                = PAGE_SHARED,
-       [VM_SHARED | VM_EXEC]                           = PAGE_READONLY_X,
+       [VM_SHARED | VM_EXEC]                           = PAGE_NONE_X,
        [VM_SHARED | VM_EXEC | VM_READ]                 = PAGE_READONLY_X,
        [VM_SHARED | VM_EXEC | VM_WRITE]                = PAGE_SHARED_X,
        [VM_SHARED | VM_EXEC | VM_WRITE | VM_READ]      = PAGE_SHARED_X
-- 
2.41.0

Reply via email to