aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2014-03-05 08:07:49 -0500
committerH. Peter Anvin <hpa@linux.intel.com>2014-03-06 13:58:18 -0500
commitd4078e232267ff53f3b030b9698a3c001db4dbec (patch)
treebb8658ced4e6610b36fbf3de05ae85c3585df850 /arch
parent0ac09f9f8cd1fb028a48330edba6023d347d3cea (diff)
x86, trace: Further robustify CR2 handling vs tracing
Building on commit 0ac09f9f8cd1 ("x86, trace: Fix CR2 corruption when tracing page faults") this patch addresses another few issues: - Now that read_cr2() is lifted into trace_do_page_fault(), we should pass the address to trace_page_fault_entries() to avoid it re-reading a potentially changed cr2. - Put both trace_do_page_fault() and trace_page_fault_entries() under CONFIG_TRACING. - Mark both fault entry functions {,trace_}do_page_fault() as notrace to avoid getting __mcount or other function entry trace callbacks before we've observed CR2. - Mark __do_page_fault() as noinline to guarantee the function tracer does get to see the fault. Cc: <jolsa@redhat.com> Cc: <vincent.weaver@maine.edu> Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20140306145300.GO9987@twins.programming.kicks-ass.net Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/mm/fault.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index e7fa28bf3262..a10c8c792161 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -1020,8 +1020,12 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs)
1020 * This routine handles page faults. It determines the address, 1020 * This routine handles page faults. It determines the address,
1021 * and the problem, and then passes it off to one of the appropriate 1021 * and the problem, and then passes it off to one of the appropriate
1022 * routines. 1022 * routines.
1023 *
1024 * This function must have noinline because both callers
1025 * {,trace_}do_page_fault() have notrace on. Having this an actual function
1026 * guarantees there's a function trace entry.
1023 */ 1027 */
1024static void __kprobes 1028static void __kprobes noinline
1025__do_page_fault(struct pt_regs *regs, unsigned long error_code, 1029__do_page_fault(struct pt_regs *regs, unsigned long error_code,
1026 unsigned long address) 1030 unsigned long address)
1027{ 1031{
@@ -1245,31 +1249,38 @@ good_area:
1245 up_read(&mm->mmap_sem); 1249 up_read(&mm->mmap_sem);
1246} 1250}
1247 1251
1248dotraplinkage void __kprobes 1252dotraplinkage void __kprobes notrace
1249do_page_fault(struct pt_regs *regs, unsigned long error_code) 1253do_page_fault(struct pt_regs *regs, unsigned long error_code)
1250{ 1254{
1255 unsigned long address = read_cr2(); /* Get the faulting address */
1251 enum ctx_state prev_state; 1256 enum ctx_state prev_state;
1252 /* Get the faulting address: */ 1257
1253 unsigned long address = read_cr2(); 1258 /*
1259 * We must have this function tagged with __kprobes, notrace and call
1260 * read_cr2() before calling anything else. To avoid calling any kind
1261 * of tracing machinery before we've observed the CR2 value.
1262 *
1263 * exception_{enter,exit}() contain all sorts of tracepoints.
1264 */
1254 1265
1255 prev_state = exception_enter(); 1266 prev_state = exception_enter();
1256 __do_page_fault(regs, error_code, address); 1267 __do_page_fault(regs, error_code, address);
1257 exception_exit(prev_state); 1268 exception_exit(prev_state);
1258} 1269}
1259 1270
1260static void trace_page_fault_entries(struct pt_regs *regs, 1271#ifdef CONFIG_TRACING
1272static void trace_page_fault_entries(unsigned long address, struct pt_regs *regs,
1261 unsigned long error_code) 1273 unsigned long error_code)
1262{ 1274{
1263 if (user_mode(regs)) 1275 if (user_mode(regs))
1264 trace_page_fault_user(read_cr2(), regs, error_code); 1276 trace_page_fault_user(address, regs, error_code);
1265 else 1277 else
1266 trace_page_fault_kernel(read_cr2(), regs, error_code); 1278 trace_page_fault_kernel(address, regs, error_code);
1267} 1279}
1268 1280
1269dotraplinkage void __kprobes 1281dotraplinkage void __kprobes notrace
1270trace_do_page_fault(struct pt_regs *regs, unsigned long error_code) 1282trace_do_page_fault(struct pt_regs *regs, unsigned long error_code)
1271{ 1283{
1272 enum ctx_state prev_state;
1273 /* 1284 /*
1274 * The exception_enter and tracepoint processing could 1285 * The exception_enter and tracepoint processing could
1275 * trigger another page faults (user space callchain 1286 * trigger another page faults (user space callchain
@@ -1277,9 +1288,11 @@ trace_do_page_fault(struct pt_regs *regs, unsigned long error_code)
1277 * the faulting address now. 1288 * the faulting address now.
1278 */ 1289 */
1279 unsigned long address = read_cr2(); 1290 unsigned long address = read_cr2();
1291 enum ctx_state prev_state;
1280 1292
1281 prev_state = exception_enter(); 1293 prev_state = exception_enter();
1282 trace_page_fault_entries(regs, error_code); 1294 trace_page_fault_entries(address, regs, error_code);
1283 __do_page_fault(regs, error_code, address); 1295 __do_page_fault(regs, error_code, address);
1284 exception_exit(prev_state); 1296 exception_exit(prev_state);
1285} 1297}
1298#endif /* CONFIG_TRACING */