2323#include <linux/sched/debug.h>
2424#include <linux/highmem.h>
2525#include <linux/perf_event.h>
26+ #include <linux/pkeys.h>
2627#include <linux/preempt.h>
2728#include <linux/hugetlb.h>
2829
@@ -486,6 +487,23 @@ static void do_bad_area(unsigned long far, unsigned long esr,
486487 }
487488}
488489
490+ static bool fault_from_pkey (unsigned long esr , struct vm_area_struct * vma ,
491+ unsigned int mm_flags )
492+ {
493+ unsigned long iss2 = ESR_ELx_ISS2 (esr );
494+
495+ if (!system_supports_poe ())
496+ return false;
497+
498+ if (esr_fsc_is_permission_fault (esr ) && (iss2 & ESR_ELx_Overlay ))
499+ return true;
500+
501+ return !arch_vma_access_permitted (vma ,
502+ mm_flags & FAULT_FLAG_WRITE ,
503+ mm_flags & FAULT_FLAG_INSTRUCTION ,
504+ false);
505+ }
506+
489507static bool is_el0_instruction_abort (unsigned long esr )
490508{
491509 return ESR_ELx_EC (esr ) == ESR_ELx_EC_IABT_LOW ;
@@ -511,6 +529,7 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
511529 unsigned long addr = untagged_addr (far );
512530 struct vm_area_struct * vma ;
513531 int si_code ;
532+ int pkey = -1 ;
514533
515534 if (kprobe_page_fault (regs , esr ))
516535 return 0 ;
@@ -575,6 +594,16 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
575594 count_vm_vma_lock_event (VMA_LOCK_SUCCESS );
576595 goto bad_area ;
577596 }
597+
598+ if (fault_from_pkey (esr , vma , mm_flags )) {
599+ pkey = vma_pkey (vma );
600+ vma_end_read (vma );
601+ fault = 0 ;
602+ si_code = SEGV_PKUERR ;
603+ count_vm_vma_lock_event (VMA_LOCK_SUCCESS );
604+ goto bad_area ;
605+ }
606+
578607 fault = handle_mm_fault (vma , addr , mm_flags | FAULT_FLAG_VMA_LOCK , regs );
579608 if (!(fault & (VM_FAULT_RETRY | VM_FAULT_COMPLETED )))
580609 vma_end_read (vma );
@@ -610,7 +639,16 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
610639 goto bad_area ;
611640 }
612641
642+ if (fault_from_pkey (esr , vma , mm_flags )) {
643+ pkey = vma_pkey (vma );
644+ mmap_read_unlock (mm );
645+ fault = 0 ;
646+ si_code = SEGV_PKUERR ;
647+ goto bad_area ;
648+ }
649+
613650 fault = handle_mm_fault (vma , addr , mm_flags , regs );
651+
614652 /* Quick path to respond to signals */
615653 if (fault_signal_pending (fault , regs )) {
616654 if (!user_mode (regs ))
@@ -669,8 +707,23 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
669707
670708 arm64_force_sig_mceerr (BUS_MCEERR_AR , far , lsb , inf -> name );
671709 } else {
710+ /*
711+ * The pkey value that we return to userspace can be different
712+ * from the pkey that caused the fault.
713+ *
714+ * 1. T1 : mprotect_key(foo, PAGE_SIZE, pkey=4);
715+ * 2. T1 : set POR_EL0 to deny access to pkey=4, touches, page
716+ * 3. T1 : faults...
717+ * 4. T2: mprotect_key(foo, PAGE_SIZE, pkey=5);
718+ * 5. T1 : enters fault handler, takes mmap_lock, etc...
719+ * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really
720+ * faulted on a pte with its pkey=4.
721+ */
672722 /* Something tried to access memory that out of memory map */
673- arm64_force_sig_fault (SIGSEGV , si_code , far , inf -> name );
723+ if (si_code == SEGV_PKUERR )
724+ arm64_force_sig_fault_pkey (far , inf -> name , pkey );
725+ else
726+ arm64_force_sig_fault (SIGSEGV , si_code , far , inf -> name );
674727 }
675728
676729 return 0 ;
0 commit comments