diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/mm/fault.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 76dcd9d8e0bc..f2fb75d46b96 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -995,6 +995,17 @@ static int fault_in_kernel_space(unsigned long address) | |||
995 | return address >= TASK_SIZE_MAX; | 995 | return address >= TASK_SIZE_MAX; |
996 | } | 996 | } |
997 | 997 | ||
998 | static inline bool smap_violation(int error_code, struct pt_regs *regs) | ||
999 | { | ||
1000 | if (error_code & PF_USER) | ||
1001 | return false; | ||
1002 | |||
1003 | if (!user_mode_vm(regs) && (regs->flags & X86_EFLAGS_AC)) | ||
1004 | return false; | ||
1005 | |||
1006 | return true; | ||
1007 | } | ||
1008 | |||
998 | /* | 1009 | /* |
999 | * This routine handles page faults. It determines the address, | 1010 | * This routine handles page faults. It determines the address, |
1000 | * and the problem, and then passes it off to one of the appropriate | 1011 | * and the problem, and then passes it off to one of the appropriate |
@@ -1088,6 +1099,13 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
1088 | if (unlikely(error_code & PF_RSVD)) | 1099 | if (unlikely(error_code & PF_RSVD)) |
1089 | pgtable_bad(regs, error_code, address); | 1100 | pgtable_bad(regs, error_code, address); |
1090 | 1101 | ||
1102 | if (static_cpu_has(X86_FEATURE_SMAP)) { | ||
1103 | if (unlikely(smap_violation(error_code, regs))) { | ||
1104 | bad_area_nosemaphore(regs, error_code, address); | ||
1105 | return; | ||
1106 | } | ||
1107 | } | ||
1108 | |||
1091 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); | 1109 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); |
1092 | 1110 | ||
1093 | /* | 1111 | /* |