@@ -118,9 +118,34 @@ static noinline int bad_area(struct pt_regs *regs, unsigned long address)
118
118
return __bad_area (regs , address , SEGV_MAPERR );
119
119
}
120
120
121
- static int bad_key_fault_exception (struct pt_regs * regs , unsigned long address ,
122
- int pkey )
121
+ #ifdef CONFIG_PPC_MEM_KEYS
122
+ static noinline int bad_access_pkey (struct pt_regs * regs , unsigned long address ,
123
+ struct vm_area_struct * vma )
123
124
{
125
+ struct mm_struct * mm = current -> mm ;
126
+ int pkey ;
127
+
128
+ /*
129
+ * We don't try to fetch the pkey from page table because reading
130
+ * page table without locking doesn't guarantee stable pte value.
131
+ * Hence the pkey value that we return to userspace can be different
132
+ * from the pkey that actually caused access error.
133
+ *
134
+ * It does *not* guarantee that the VMA we find here
135
+ * was the one that we faulted on.
136
+ *
137
+ * 1. T1 : mprotect_key(foo, PAGE_SIZE, pkey=4);
138
+ * 2. T1 : set AMR to deny access to pkey=4, touches, page
139
+ * 3. T1 : faults...
140
+ * 4. T2: mprotect_key(foo, PAGE_SIZE, pkey=5);
141
+ * 5. T1 : enters fault handler, takes mmap_sem, etc...
142
+ * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really
143
+ * faulted on a pte with its pkey=4.
144
+ */
145
+ pkey = vma_pkey (vma );
146
+
147
+ up_read (& mm -> mmap_sem );
148
+
124
149
/*
125
150
* If we are in kernel mode, bail out with a SEGV, this will
126
151
* be caught by the assembly which will restore the non-volatile
@@ -133,6 +158,7 @@ static int bad_key_fault_exception(struct pt_regs *regs, unsigned long address,
133
158
134
159
return 0 ;
135
160
}
161
+ #endif
136
162
137
163
static noinline int bad_access (struct pt_regs * regs , unsigned long address )
138
164
{
@@ -289,8 +315,31 @@ static bool bad_stack_expansion(struct pt_regs *regs, unsigned long address,
289
315
return false;
290
316
}
291
317
292
- static bool access_error (bool is_write , bool is_exec ,
293
- struct vm_area_struct * vma )
318
+ #ifdef CONFIG_PPC_MEM_KEYS
319
+ static bool access_pkey_error (bool is_write , bool is_exec , bool is_pkey ,
320
+ struct vm_area_struct * vma )
321
+ {
322
+ /*
323
+ * Read or write was blocked by protection keys. This is
324
+ * always an unconditional error and can never result in
325
+ * a follow-up action to resolve the fault, like a COW.
326
+ */
327
+ if (is_pkey )
328
+ return true;
329
+
330
+ /*
331
+ * Make sure to check the VMA so that we do not perform
332
+ * faults just to hit a pkey fault as soon as we fill in a
333
+ * page. Only called for current mm, hence foreign == 0
334
+ */
335
+ if (!arch_vma_access_permitted (vma , is_write , is_exec , 0 ))
336
+ return true;
337
+
338
+ return false;
339
+ }
340
+ #endif
341
+
342
+ static bool access_error (bool is_write , bool is_exec , struct vm_area_struct * vma )
294
343
{
295
344
/*
296
345
* Allow execution from readable areas if the MMU does not
@@ -483,10 +532,6 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
483
532
484
533
perf_sw_event (PERF_COUNT_SW_PAGE_FAULTS , 1 , regs , address );
485
534
486
- if (error_code & DSISR_KEYFAULT )
487
- return bad_key_fault_exception (regs , address ,
488
- get_mm_addr_key (mm , address ));
489
-
490
535
/*
491
536
* We want to do this outside mmap_sem, because reading code around nip
492
537
* can result in fault, which will cause a deadlock when called with
@@ -555,6 +600,13 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
555
600
return bad_area (regs , address );
556
601
557
602
good_area :
603
+
604
+ #ifdef CONFIG_PPC_MEM_KEYS
605
+ if (unlikely (access_pkey_error (is_write , is_exec ,
606
+ (error_code & DSISR_KEYFAULT ), vma )))
607
+ return bad_access_pkey (regs , address , vma );
608
+ #endif /* CONFIG_PPC_MEM_KEYS */
609
+
558
610
if (unlikely (access_error (is_write , is_exec , vma )))
559
611
return bad_access (regs , address );
560
612
@@ -565,21 +617,6 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
565
617
*/
566
618
fault = handle_mm_fault (vma , address , flags );
567
619
568
- #ifdef CONFIG_PPC_MEM_KEYS
569
- /*
570
- * we skipped checking for access error due to key earlier.
571
- * Check that using handle_mm_fault error return.
572
- */
573
- if (unlikely (fault & VM_FAULT_SIGSEGV ) &&
574
- !arch_vma_access_permitted (vma , is_write , is_exec , 0 )) {
575
-
576
- int pkey = vma_pkey (vma );
577
-
578
- up_read (& mm -> mmap_sem );
579
- return bad_key_fault_exception (regs , address , pkey );
580
- }
581
- #endif /* CONFIG_PPC_MEM_KEYS */
582
-
583
620
major |= fault & VM_FAULT_MAJOR ;
584
621
585
622
if (fault_signal_pending (fault , regs ))
0 commit comments