aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/fault.c')
-rw-r--r--arch/x86/mm/fault.c61
1 files changed, 42 insertions, 19 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 9d591c895803..a10c8c792161 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -1001,6 +1001,12 @@ static int fault_in_kernel_space(unsigned long address)
1001 1001
1002static inline bool smap_violation(int error_code, struct pt_regs *regs) 1002static inline bool smap_violation(int error_code, struct pt_regs *regs)
1003{ 1003{
1004 if (!IS_ENABLED(CONFIG_X86_SMAP))
1005 return false;
1006
1007 if (!static_cpu_has(X86_FEATURE_SMAP))
1008 return false;
1009
1004 if (error_code & PF_USER) 1010 if (error_code & PF_USER)
1005 return false; 1011 return false;
1006 1012
@@ -1014,13 +1020,17 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs)
1014 * This routine handles page faults. It determines the address, 1020 * This routine handles page faults. It determines the address,
1015 * 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
1016 * 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.
1017 */ 1027 */
1018static void __kprobes 1028static void __kprobes noinline
1019__do_page_fault(struct pt_regs *regs, unsigned long error_code) 1029__do_page_fault(struct pt_regs *regs, unsigned long error_code,
1030 unsigned long address)
1020{ 1031{
1021 struct vm_area_struct *vma; 1032 struct vm_area_struct *vma;
1022 struct task_struct *tsk; 1033 struct task_struct *tsk;
1023 unsigned long address;
1024 struct mm_struct *mm; 1034 struct mm_struct *mm;
1025 int fault; 1035 int fault;
1026 unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; 1036 unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
@@ -1028,9 +1038,6 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
1028 tsk = current; 1038 tsk = current;
1029 mm = tsk->mm; 1039 mm = tsk->mm;
1030 1040
1031 /* Get the faulting address: */
1032 address = read_cr2();
1033
1034 /* 1041 /*
1035 * Detect and handle instructions that would cause a page fault for 1042 * Detect and handle instructions that would cause a page fault for
1036 * both a tracked kernel page and a userspace page. 1043 * both a tracked kernel page and a userspace page.
@@ -1087,11 +1094,9 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
1087 if (unlikely(error_code & PF_RSVD)) 1094 if (unlikely(error_code & PF_RSVD))
1088 pgtable_bad(regs, error_code, address); 1095 pgtable_bad(regs, error_code, address);
1089 1096
1090 if (static_cpu_has(X86_FEATURE_SMAP)) { 1097 if (unlikely(smap_violation(error_code, regs))) {
1091 if (unlikely(smap_violation(error_code, regs))) { 1098 bad_area_nosemaphore(regs, error_code, address);
1092 bad_area_nosemaphore(regs, error_code, address); 1099 return;
1093 return;
1094 }
1095 } 1100 }
1096 1101
1097 /* 1102 /*
@@ -1244,32 +1249,50 @@ good_area:
1244 up_read(&mm->mmap_sem); 1249 up_read(&mm->mmap_sem);
1245} 1250}
1246 1251
1247dotraplinkage void __kprobes 1252dotraplinkage void __kprobes notrace
1248do_page_fault(struct pt_regs *regs, unsigned long error_code) 1253do_page_fault(struct pt_regs *regs, unsigned long error_code)
1249{ 1254{
1255 unsigned long address = read_cr2(); /* Get the faulting address */
1250 enum ctx_state prev_state; 1256 enum ctx_state prev_state;
1251 1257
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 */
1265
1252 prev_state = exception_enter(); 1266 prev_state = exception_enter();
1253 __do_page_fault(regs, error_code); 1267 __do_page_fault(regs, error_code, address);
1254 exception_exit(prev_state); 1268 exception_exit(prev_state);
1255} 1269}
1256 1270
1257static 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,
1258 unsigned long error_code) 1273 unsigned long error_code)
1259{ 1274{
1260 if (user_mode(regs)) 1275 if (user_mode(regs))
1261 trace_page_fault_user(read_cr2(), regs, error_code); 1276 trace_page_fault_user(address, regs, error_code);
1262 else 1277 else
1263 trace_page_fault_kernel(read_cr2(), regs, error_code); 1278 trace_page_fault_kernel(address, regs, error_code);
1264} 1279}
1265 1280
1266dotraplinkage void __kprobes 1281dotraplinkage void __kprobes notrace
1267trace_do_page_fault(struct pt_regs *regs, unsigned long error_code) 1282trace_do_page_fault(struct pt_regs *regs, unsigned long error_code)
1268{ 1283{
1284 /*
1285 * The exception_enter and tracepoint processing could
1286 * trigger another page faults (user space callchain
1287 * reading) and destroy the original cr2 value, so read
1288 * the faulting address now.
1289 */
1290 unsigned long address = read_cr2();
1269 enum ctx_state prev_state; 1291 enum ctx_state prev_state;
1270 1292
1271 prev_state = exception_enter(); 1293 prev_state = exception_enter();
1272 trace_page_fault_entries(regs, error_code); 1294 trace_page_fault_entries(address, regs, error_code);
1273 __do_page_fault(regs, error_code); 1295 __do_page_fault(regs, error_code, address);
1274 exception_exit(prev_state); 1296 exception_exit(prev_state);
1275} 1297}
1298#endif /* CONFIG_TRACING */