]> git.baikalelectronics.ru Git - kernel.git/commitdiff
powerpc/mm: Support execute-only memory on the Radix MMU
authorRussell Currey <ruscur@russell.cc>
Wed, 17 Aug 2022 05:06:39 +0000 (15:06 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Fri, 26 Aug 2022 01:02:21 +0000 (11:02 +1000)
Add support for execute-only memory (XOM) for the Radix MMU by using an
execute-only mapping, as opposed to the RX mapping used by powerpc's
other MMUs.

The Hash MMU already supports XOM through the execute-only pkey,
which is a separate mechanism shared with x86.  A PROT_EXEC-only mapping
will map to RX, and then the pkey will be applied on top of it.

mmap() and mprotect() consumers in userspace should observe the same
behaviour on Hash and Radix despite the differences in implementation.

Replacing the vma_is_accessible() check in access_error() with a read
check should be functionally equivalent for non-Radix MMUs, since it
follows write and execute checks.  For Radix, the change enables
detecting faults on execute-only mappings where vma_is_accessible() would
return true.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20220817050640.406017-1-ruscur@russell.cc
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/mm/book3s64/pgtable.c
arch/powerpc/mm/fault.c

index 392ff48f77df34b4e809138612e56eb4114b0666..486902aff040ca1c1bc347e8ebc51f477c038f1b 100644 (file)
 #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)
index 7b9966402b25bc4e26b5fdc300e54932b367bd8e..f6151a5892982ac288934e3ce0f3533bb4743911 100644 (file)
@@ -553,8 +553,15 @@ EXPORT_SYMBOL_GPL(memremap_compat_align);
 
 pgprot_t vm_get_page_prot(unsigned long vm_flags)
 {
-       unsigned long prot = pgprot_val(protection_map[vm_flags &
-                                       (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]);
+       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 (vm_flags & VM_SAO)
                prot |= _PAGE_SAO;
index 01400542868731439de4b6a3ff20c058215cc2d2..1566804e4b3da6f1e9dd97039735a6d1f0d9616e 100644 (file)
@@ -270,7 +270,11 @@ static bool access_error(bool is_write, bool is_exec, struct vm_area_struct *vma
                return false;
        }
 
-       if (unlikely(!vma_is_accessible(vma)))
+       /*
+        * Check for a read fault.  This could be caused by a read on an
+        * inaccessible page (i.e. PROT_NONE), or a Radix MMU execute-only page.
+        */
+       if (unlikely(!(vma->vm_flags & VM_READ)))
                return true;
        /*
         * We should ideally do the vma pkey access check here. But in the