23
23
#include <linux/sched/debug.h>
24
24
#include <linux/highmem.h>
25
25
#include <linux/perf_event.h>
26
+ #include <linux/pkeys.h>
26
27
#include <linux/preempt.h>
27
28
#include <linux/hugetlb.h>
28
29
@@ -486,6 +487,23 @@ static void do_bad_area(unsigned long far, unsigned long esr,
486
487
}
487
488
}
488
489
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
+
489
507
static bool is_el0_instruction_abort (unsigned long esr )
490
508
{
491
509
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,
511
529
unsigned long addr = untagged_addr (far );
512
530
struct vm_area_struct * vma ;
513
531
int si_code ;
532
+ int pkey = -1 ;
514
533
515
534
if (kprobe_page_fault (regs , esr ))
516
535
return 0 ;
@@ -575,6 +594,16 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
575
594
count_vm_vma_lock_event (VMA_LOCK_SUCCESS );
576
595
goto bad_area ;
577
596
}
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
+
578
607
fault = handle_mm_fault (vma , addr , mm_flags | FAULT_FLAG_VMA_LOCK , regs );
579
608
if (!(fault & (VM_FAULT_RETRY | VM_FAULT_COMPLETED )))
580
609
vma_end_read (vma );
@@ -610,7 +639,16 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
610
639
goto bad_area ;
611
640
}
612
641
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
+
613
650
fault = handle_mm_fault (vma , addr , mm_flags , regs );
651
+
614
652
/* Quick path to respond to signals */
615
653
if (fault_signal_pending (fault , regs )) {
616
654
if (!user_mode (regs ))
@@ -669,8 +707,23 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
669
707
670
708
arm64_force_sig_mceerr (BUS_MCEERR_AR , far , lsb , inf -> name );
671
709
} 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
+ */
672
722
/* 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 );
674
727
}
675
728
676
729
return 0 ;
0 commit comments