diff options
| -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 | } |
