diff options
Diffstat (limited to 'arch/x86/mm/fault.c')
-rw-r--r-- | arch/x86/mm/fault.c | 50 |
1 files changed, 25 insertions, 25 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index b836a7274e12..e2baeaa053a5 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -192,8 +192,7 @@ is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr) | |||
192 | * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really | 192 | * 6. T1 : reaches here, sees vma_pkey(vma)=5, when we really |
193 | * faulted on a pte with its pkey=4. | 193 | * faulted on a pte with its pkey=4. |
194 | */ | 194 | */ |
195 | static void fill_sig_info_pkey(int si_code, siginfo_t *info, | 195 | static void fill_sig_info_pkey(int si_code, siginfo_t *info, u32 *pkey) |
196 | struct vm_area_struct *vma) | ||
197 | { | 196 | { |
198 | /* This is effectively an #ifdef */ | 197 | /* This is effectively an #ifdef */ |
199 | if (!boot_cpu_has(X86_FEATURE_OSPKE)) | 198 | if (!boot_cpu_has(X86_FEATURE_OSPKE)) |
@@ -209,7 +208,7 @@ static void fill_sig_info_pkey(int si_code, siginfo_t *info, | |||
209 | * valid VMA, so we should never reach this without a | 208 | * valid VMA, so we should never reach this without a |
210 | * valid VMA. | 209 | * valid VMA. |
211 | */ | 210 | */ |
212 | if (!vma) { | 211 | if (!pkey) { |
213 | WARN_ONCE(1, "PKU fault with no VMA passed in"); | 212 | WARN_ONCE(1, "PKU fault with no VMA passed in"); |
214 | info->si_pkey = 0; | 213 | info->si_pkey = 0; |
215 | return; | 214 | return; |
@@ -219,13 +218,12 @@ static void fill_sig_info_pkey(int si_code, siginfo_t *info, | |||
219 | * absolutely guranteed to be 100% accurate because of | 218 | * absolutely guranteed to be 100% accurate because of |
220 | * the race explained above. | 219 | * the race explained above. |
221 | */ | 220 | */ |
222 | info->si_pkey = vma_pkey(vma); | 221 | info->si_pkey = *pkey; |
223 | } | 222 | } |
224 | 223 | ||
225 | static void | 224 | static void |
226 | force_sig_info_fault(int si_signo, int si_code, unsigned long address, | 225 | force_sig_info_fault(int si_signo, int si_code, unsigned long address, |
227 | struct task_struct *tsk, struct vm_area_struct *vma, | 226 | struct task_struct *tsk, u32 *pkey, int fault) |
228 | int fault) | ||
229 | { | 227 | { |
230 | unsigned lsb = 0; | 228 | unsigned lsb = 0; |
231 | siginfo_t info; | 229 | siginfo_t info; |
@@ -240,7 +238,7 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long address, | |||
240 | lsb = PAGE_SHIFT; | 238 | lsb = PAGE_SHIFT; |
241 | info.si_addr_lsb = lsb; | 239 | info.si_addr_lsb = lsb; |
242 | 240 | ||
243 | fill_sig_info_pkey(si_code, &info, vma); | 241 | fill_sig_info_pkey(si_code, &info, pkey); |
244 | 242 | ||
245 | force_sig_info(si_signo, &info, tsk); | 243 | force_sig_info(si_signo, &info, tsk); |
246 | } | 244 | } |
@@ -762,8 +760,6 @@ no_context(struct pt_regs *regs, unsigned long error_code, | |||
762 | struct task_struct *tsk = current; | 760 | struct task_struct *tsk = current; |
763 | unsigned long flags; | 761 | unsigned long flags; |
764 | int sig; | 762 | int sig; |
765 | /* No context means no VMA to pass down */ | ||
766 | struct vm_area_struct *vma = NULL; | ||
767 | 763 | ||
768 | /* Are we prepared to handle this kernel fault? */ | 764 | /* Are we prepared to handle this kernel fault? */ |
769 | if (fixup_exception(regs, X86_TRAP_PF)) { | 765 | if (fixup_exception(regs, X86_TRAP_PF)) { |
@@ -788,7 +784,7 @@ no_context(struct pt_regs *regs, unsigned long error_code, | |||
788 | 784 | ||
789 | /* XXX: hwpoison faults will set the wrong code. */ | 785 | /* XXX: hwpoison faults will set the wrong code. */ |
790 | force_sig_info_fault(signal, si_code, address, | 786 | force_sig_info_fault(signal, si_code, address, |
791 | tsk, vma, 0); | 787 | tsk, NULL, 0); |
792 | } | 788 | } |
793 | 789 | ||
794 | /* | 790 | /* |
@@ -806,7 +802,6 @@ no_context(struct pt_regs *regs, unsigned long error_code, | |||
806 | if (is_vmalloc_addr((void *)address) && | 802 | if (is_vmalloc_addr((void *)address) && |
807 | (((unsigned long)tsk->stack - 1 - address < PAGE_SIZE) || | 803 | (((unsigned long)tsk->stack - 1 - address < PAGE_SIZE) || |
808 | address - ((unsigned long)tsk->stack + THREAD_SIZE) < PAGE_SIZE)) { | 804 | address - ((unsigned long)tsk->stack + THREAD_SIZE) < PAGE_SIZE)) { |
809 | register void *__sp asm("rsp"); | ||
810 | unsigned long stack = this_cpu_read(orig_ist.ist[DOUBLEFAULT_STACK]) - sizeof(void *); | 805 | unsigned long stack = this_cpu_read(orig_ist.ist[DOUBLEFAULT_STACK]) - sizeof(void *); |
811 | /* | 806 | /* |
812 | * We're likely to be running with very little stack space | 807 | * We're likely to be running with very little stack space |
@@ -821,7 +816,7 @@ no_context(struct pt_regs *regs, unsigned long error_code, | |||
821 | asm volatile ("movq %[stack], %%rsp\n\t" | 816 | asm volatile ("movq %[stack], %%rsp\n\t" |
822 | "call handle_stack_overflow\n\t" | 817 | "call handle_stack_overflow\n\t" |
823 | "1: jmp 1b" | 818 | "1: jmp 1b" |
824 | : "+r" (__sp) | 819 | : ASM_CALL_CONSTRAINT |
825 | : "D" ("kernel stack overflow (page fault)"), | 820 | : "D" ("kernel stack overflow (page fault)"), |
826 | "S" (regs), "d" (address), | 821 | "S" (regs), "d" (address), |
827 | [stack] "rm" (stack)); | 822 | [stack] "rm" (stack)); |
@@ -897,8 +892,7 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code, | |||
897 | 892 | ||
898 | static void | 893 | static void |
899 | __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, | 894 | __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, |
900 | unsigned long address, struct vm_area_struct *vma, | 895 | unsigned long address, u32 *pkey, int si_code) |
901 | int si_code) | ||
902 | { | 896 | { |
903 | struct task_struct *tsk = current; | 897 | struct task_struct *tsk = current; |
904 | 898 | ||
@@ -946,7 +940,7 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, | |||
946 | tsk->thread.error_code = error_code; | 940 | tsk->thread.error_code = error_code; |
947 | tsk->thread.trap_nr = X86_TRAP_PF; | 941 | tsk->thread.trap_nr = X86_TRAP_PF; |
948 | 942 | ||
949 | force_sig_info_fault(SIGSEGV, si_code, address, tsk, vma, 0); | 943 | force_sig_info_fault(SIGSEGV, si_code, address, tsk, pkey, 0); |
950 | 944 | ||
951 | return; | 945 | return; |
952 | } | 946 | } |
@@ -959,9 +953,9 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, | |||
959 | 953 | ||
960 | static noinline void | 954 | static noinline void |
961 | bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, | 955 | bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, |
962 | unsigned long address, struct vm_area_struct *vma) | 956 | unsigned long address, u32 *pkey) |
963 | { | 957 | { |
964 | __bad_area_nosemaphore(regs, error_code, address, vma, SEGV_MAPERR); | 958 | __bad_area_nosemaphore(regs, error_code, address, pkey, SEGV_MAPERR); |
965 | } | 959 | } |
966 | 960 | ||
967 | static void | 961 | static void |
@@ -969,6 +963,10 @@ __bad_area(struct pt_regs *regs, unsigned long error_code, | |||
969 | unsigned long address, struct vm_area_struct *vma, int si_code) | 963 | unsigned long address, struct vm_area_struct *vma, int si_code) |
970 | { | 964 | { |
971 | struct mm_struct *mm = current->mm; | 965 | struct mm_struct *mm = current->mm; |
966 | u32 pkey; | ||
967 | |||
968 | if (vma) | ||
969 | pkey = vma_pkey(vma); | ||
972 | 970 | ||
973 | /* | 971 | /* |
974 | * Something tried to access memory that isn't in our memory map.. | 972 | * Something tried to access memory that isn't in our memory map.. |
@@ -976,7 +974,8 @@ __bad_area(struct pt_regs *regs, unsigned long error_code, | |||
976 | */ | 974 | */ |
977 | up_read(&mm->mmap_sem); | 975 | up_read(&mm->mmap_sem); |
978 | 976 | ||
979 | __bad_area_nosemaphore(regs, error_code, address, vma, si_code); | 977 | __bad_area_nosemaphore(regs, error_code, address, |
978 | (vma) ? &pkey : NULL, si_code); | ||
980 | } | 979 | } |
981 | 980 | ||
982 | static noinline void | 981 | static noinline void |
@@ -1019,7 +1018,7 @@ bad_area_access_error(struct pt_regs *regs, unsigned long error_code, | |||
1019 | 1018 | ||
1020 | static void | 1019 | static void |
1021 | do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, | 1020 | do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, |
1022 | struct vm_area_struct *vma, unsigned int fault) | 1021 | u32 *pkey, unsigned int fault) |
1023 | { | 1022 | { |
1024 | struct task_struct *tsk = current; | 1023 | struct task_struct *tsk = current; |
1025 | int code = BUS_ADRERR; | 1024 | int code = BUS_ADRERR; |
@@ -1046,13 +1045,12 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address, | |||
1046 | code = BUS_MCEERR_AR; | 1045 | code = BUS_MCEERR_AR; |
1047 | } | 1046 | } |
1048 | #endif | 1047 | #endif |
1049 | force_sig_info_fault(SIGBUS, code, address, tsk, vma, fault); | 1048 | force_sig_info_fault(SIGBUS, code, address, tsk, pkey, fault); |
1050 | } | 1049 | } |
1051 | 1050 | ||
1052 | static noinline void | 1051 | static noinline void |
1053 | mm_fault_error(struct pt_regs *regs, unsigned long error_code, | 1052 | mm_fault_error(struct pt_regs *regs, unsigned long error_code, |
1054 | unsigned long address, struct vm_area_struct *vma, | 1053 | unsigned long address, u32 *pkey, unsigned int fault) |
1055 | unsigned int fault) | ||
1056 | { | 1054 | { |
1057 | if (fatal_signal_pending(current) && !(error_code & PF_USER)) { | 1055 | if (fatal_signal_pending(current) && !(error_code & PF_USER)) { |
1058 | no_context(regs, error_code, address, 0, 0); | 1056 | no_context(regs, error_code, address, 0, 0); |
@@ -1076,9 +1074,9 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, | |||
1076 | } else { | 1074 | } else { |
1077 | if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON| | 1075 | if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON| |
1078 | VM_FAULT_HWPOISON_LARGE)) | 1076 | VM_FAULT_HWPOISON_LARGE)) |
1079 | do_sigbus(regs, error_code, address, vma, fault); | 1077 | do_sigbus(regs, error_code, address, pkey, fault); |
1080 | else if (fault & VM_FAULT_SIGSEGV) | 1078 | else if (fault & VM_FAULT_SIGSEGV) |
1081 | bad_area_nosemaphore(regs, error_code, address, vma); | 1079 | bad_area_nosemaphore(regs, error_code, address, pkey); |
1082 | else | 1080 | else |
1083 | BUG(); | 1081 | BUG(); |
1084 | } | 1082 | } |
@@ -1268,6 +1266,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, | |||
1268 | struct mm_struct *mm; | 1266 | struct mm_struct *mm; |
1269 | int fault, major = 0; | 1267 | int fault, major = 0; |
1270 | unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; | 1268 | unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; |
1269 | u32 pkey; | ||
1271 | 1270 | ||
1272 | tsk = current; | 1271 | tsk = current; |
1273 | mm = tsk->mm; | 1272 | mm = tsk->mm; |
@@ -1468,9 +1467,10 @@ good_area: | |||
1468 | return; | 1467 | return; |
1469 | } | 1468 | } |
1470 | 1469 | ||
1470 | pkey = vma_pkey(vma); | ||
1471 | up_read(&mm->mmap_sem); | 1471 | up_read(&mm->mmap_sem); |
1472 | if (unlikely(fault & VM_FAULT_ERROR)) { | 1472 | if (unlikely(fault & VM_FAULT_ERROR)) { |
1473 | mm_fault_error(regs, error_code, address, vma, fault); | 1473 | mm_fault_error(regs, error_code, address, &pkey, fault); |
1474 | return; | 1474 | return; |
1475 | } | 1475 | } |
1476 | 1476 | ||