aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@redhat.com>2014-02-28 11:05:26 -0500
committerH. Peter Anvin <hpa@linux.intel.com>2014-03-04 19:00:14 -0500
commit0ac09f9f8cd1fb028a48330edba6023d347d3cea (patch)
tree6c0552e39b416d90334dd488fe7ce82e3318bb46 /arch/x86
parent3c0b566334c9942c89927bd1b5ad2f32baab81fa (diff)
x86, trace: Fix CR2 corruption when tracing page faults
The trace_do_page_fault function trigger tracepoint and then handles the actual page fault. This could lead to error if the tracepoint caused page fault. The original cr2 value gets lost and the original page fault handler kills current process with SIGSEGV. This happens if you record page faults with callchain data, the user part of it will cause tracepoint handler to page fault: # perf record -g -e exceptions:page_fault_user ls Fixing this by saving the original cr2 value and using it after tracepoint handler is done. v2: Moving the cr2 read before exception_enter, because it could trigger tracepoint as well. Reported-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Reported-by: Vince Weaver <vincent.weaver@maine.edu> Tested-by: Vince Weaver <vincent.weaver@maine.edu> Acked-by: Steven Rostedt <rostedt@goodmis.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Seiji Aguchi <seiji.aguchi@hds.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> Link: http://lkml.kernel.org/r/alpine.DEB.2.10.1402211701380.6395@vincent-weaver-1.um.maine.edu Link: http://lkml.kernel.org/r/20140228160526.GD1133@krava.brq.redhat.com
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/mm/fault.c20
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 */
1024static void __kprobes 1024static 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
1252do_page_fault(struct pt_regs *regs, unsigned long error_code) 1249do_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
1271trace_do_page_fault(struct pt_regs *regs, unsigned long error_code) 1270trace_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}