powerpc: Handle exceptions caused by pkey violation
authorRam Pai <linuxram@us.ibm.com>
Fri, 19 Jan 2018 01:50:40 +0000 (17:50 -0800)
committerMichael Ellerman <mpe@ellerman.id.au>
Sat, 20 Jan 2018 11:59:04 +0000 (22:59 +1100)
Handle Data and  Instruction exceptions caused by memory
protection-key.

The CPU will detect the key fault if the HPTE is already
programmed with the key.

However if the HPTE is not  hashed, a key fault will not
be detected by the hardware. The software will detect
pkey violation in such a case.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/reg.h
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/mm/fault.c

index b779f3ccd4126d2de2ab8303654bef44a6a2af58..ffc9990e8040727843dd7a472ba82a3620cba85a 100644 (file)
                                 DSISR_BAD_EXT_CTRL)
 #define          DSISR_BAD_FAULT_64S   (DSISR_BAD_FAULT_32S    | \
                                 DSISR_ATTR_CONFLICT    | \
-                                DSISR_KEYFAULT         | \
                                 DSISR_UNSUPP_MMU       | \
                                 DSISR_PRTABLE_FAULT    | \
                                 DSISR_ICSWX_NO_CT      | \
index 1a4f51f35870857531a7d585fe277d3b34bc9d89..42a47d83282cfbd7dab42a242421b2e4cfb237cc 100644 (file)
@@ -1527,7 +1527,7 @@ USE_TEXT_SECTION()
        .balign IFETCH_ALIGN_BYTES
 do_hash_page:
 #ifdef CONFIG_PPC_BOOK3S_64
-       lis     r0,(DSISR_BAD_FAULT_64S|DSISR_DABRMATCH)@h
+       lis     r0,(DSISR_BAD_FAULT_64S | DSISR_DABRMATCH | DSISR_KEYFAULT)@h
        ori     r0,r0,DSISR_BAD_FAULT_64S@l
        and.    r0,r4,r0                /* weird error? */
        bne-    handle_page_fault       /* if not, try to insert a HPTE */
index c07896c1951768eb2c0489a82a172978a48f2b19..6417a659b02d6cbd4446646bc9fc777f3dd7f962 100644 (file)
@@ -427,6 +427,11 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
+       if (error_code & DSISR_KEYFAULT) {
+               _exception(SIGSEGV, regs, SEGV_PKUERR, address);
+               return 0;
+       }
+
        /*
         * We want to do this outside mmap_sem, because reading code around nip
         * can result in fault, which will cause a deadlock when called with
@@ -498,6 +503,23 @@ good_area:
         * the fault.
         */
        fault = handle_mm_fault(vma, address, flags);
+
+#ifdef CONFIG_PPC_MEM_KEYS
+       /*
+        * if the HPTE is not hashed, hardware will not detect
+        * a key fault. Lets check if we failed because of a
+        * software detected key fault.
+        */
+       if (unlikely(fault & VM_FAULT_SIGSEGV) &&
+               !arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
+                       is_exec, 0)) {
+               int pkey = vma_pkey(vma);
+
+               if (likely(pkey))
+                       return __bad_area(regs, address, SEGV_PKUERR);
+       }
+#endif /* CONFIG_PPC_MEM_KEYS */
+
        major |= fault & VM_FAULT_MAJOR;
 
        /*