diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/mm/fault.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 6dea040cc3a1..e7fa28bf3262 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -1022,11 +1022,11 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs) | |||
1022 | * routines. | 1022 | * routines. |
1023 | */ | 1023 | */ |
1024 | static void __kprobes | 1024 | static void __kprobes |
1025 | __do_page_fault(struct pt_regs *regs, unsigned long error_code) | 1025 | __do_page_fault(struct pt_regs *regs, unsigned long error_code, |
1026 | unsigned long address) | ||
1026 | { | 1027 | { |
1027 | struct vm_area_struct *vma; | 1028 | struct vm_area_struct *vma; |
1028 | struct task_struct *tsk; | 1029 | struct task_struct *tsk; |
1029 | unsigned long address; | ||
1030 | struct mm_struct *mm; | 1030 | struct mm_struct *mm; |
1031 | int fault; | 1031 | int fault; |
1032 | unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; | 1032 | unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; |
@@ -1034,9 +1034,6 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
1034 | tsk = current; | 1034 | tsk = current; |
1035 | mm = tsk->mm; | 1035 | mm = tsk->mm; |
1036 | 1036 | ||
1037 | /* Get the faulting address: */ | ||
1038 | address = read_cr2(); | ||
1039 | |||
1040 | /* | 1037 | /* |
1041 | * Detect and handle instructions that would cause a page fault for | 1038 | * Detect and handle instructions that would cause a page fault for |
1042 | * both a tracked kernel page and a userspace page. | 1039 | * both a tracked kernel page and a userspace page. |
@@ -1252,9 +1249,11 @@ dotraplinkage void __kprobes | |||
1252 | do_page_fault(struct pt_regs *regs, unsigned long error_code) | 1249 | do_page_fault(struct pt_regs *regs, unsigned long error_code) |
1253 | { | 1250 | { |
1254 | enum ctx_state prev_state; | 1251 | enum ctx_state prev_state; |
1252 | /* Get the faulting address: */ | ||
1253 | unsigned long address = read_cr2(); | ||
1255 | 1254 | ||
1256 | prev_state = exception_enter(); | 1255 | prev_state = exception_enter(); |
1257 | __do_page_fault(regs, error_code); | 1256 | __do_page_fault(regs, error_code, address); |
1258 | exception_exit(prev_state); | 1257 | exception_exit(prev_state); |
1259 | } | 1258 | } |
1260 | 1259 | ||
@@ -1271,9 +1270,16 @@ dotraplinkage void __kprobes | |||
1271 | trace_do_page_fault(struct pt_regs *regs, unsigned long error_code) | 1270 | trace_do_page_fault(struct pt_regs *regs, unsigned long error_code) |
1272 | { | 1271 | { |
1273 | enum ctx_state prev_state; | 1272 | enum ctx_state prev_state; |
1273 | /* | ||
1274 | * The exception_enter and tracepoint processing could | ||
1275 | * trigger another page faults (user space callchain | ||
1276 | * reading) and destroy the original cr2 value, so read | ||
1277 | * the faulting address now. | ||
1278 | */ | ||
1279 | unsigned long address = read_cr2(); | ||
1274 | 1280 | ||
1275 | prev_state = exception_enter(); | 1281 | prev_state = exception_enter(); |
1276 | trace_page_fault_entries(regs, error_code); | 1282 | trace_page_fault_entries(regs, error_code); |
1277 | __do_page_fault(regs, error_code); | 1283 | __do_page_fault(regs, error_code, address); |
1278 | exception_exit(prev_state); | 1284 | exception_exit(prev_state); |
1279 | } | 1285 | } |