aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/kvm.c6
-rw-r--r--arch/x86/kernel/traps.c65
-rw-r--r--arch/x86/mm/fault.c6
-rw-r--r--include/linux/context_tracking.h19
4 files changed, 61 insertions, 35 deletions
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index e8bb0d61ecdc..cd6d9a5a42f6 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -254,16 +254,18 @@ EXPORT_SYMBOL_GPL(kvm_read_and_reset_pf_reason);
254dotraplinkage void __kprobes 254dotraplinkage void __kprobes
255do_async_page_fault(struct pt_regs *regs, unsigned long error_code) 255do_async_page_fault(struct pt_regs *regs, unsigned long error_code)
256{ 256{
257 enum ctx_state prev_state;
258
257 switch (kvm_read_and_reset_pf_reason()) { 259 switch (kvm_read_and_reset_pf_reason()) {
258 default: 260 default:
259 do_page_fault(regs, error_code); 261 do_page_fault(regs, error_code);
260 break; 262 break;
261 case KVM_PV_REASON_PAGE_NOT_PRESENT: 263 case KVM_PV_REASON_PAGE_NOT_PRESENT:
262 /* page is swapped out by the host. */ 264 /* page is swapped out by the host. */
263 exception_enter(regs); 265 prev_state = exception_enter();
264 exit_idle(); 266 exit_idle();
265 kvm_async_pf_task_wait((u32)read_cr2()); 267 kvm_async_pf_task_wait((u32)read_cr2());
266 exception_exit(regs); 268 exception_exit(prev_state);
267 break; 269 break;
268 case KVM_PV_REASON_PAGE_READY: 270 case KVM_PV_REASON_PAGE_READY:
269 rcu_irq_enter(); 271 rcu_irq_enter();
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index ecc4ccbdd0cf..ff6d2271cbe2 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -175,34 +175,38 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
175#define DO_ERROR(trapnr, signr, str, name) \ 175#define DO_ERROR(trapnr, signr, str, name) \
176dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ 176dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
177{ \ 177{ \
178 exception_enter(regs); \ 178 enum ctx_state prev_state; \
179 \
180 prev_state = exception_enter(); \
179 if (notify_die(DIE_TRAP, str, regs, error_code, \ 181 if (notify_die(DIE_TRAP, str, regs, error_code, \
180 trapnr, signr) == NOTIFY_STOP) { \ 182 trapnr, signr) == NOTIFY_STOP) { \
181 exception_exit(regs); \ 183 exception_exit(prev_state); \
182 return; \ 184 return; \
183 } \ 185 } \
184 conditional_sti(regs); \ 186 conditional_sti(regs); \
185 do_trap(trapnr, signr, str, regs, error_code, NULL); \ 187 do_trap(trapnr, signr, str, regs, error_code, NULL); \
186 exception_exit(regs); \ 188 exception_exit(prev_state); \
187} 189}
188 190
189#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ 191#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
190dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ 192dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
191{ \ 193{ \
192 siginfo_t info; \ 194 siginfo_t info; \
195 enum ctx_state prev_state; \
196 \
193 info.si_signo = signr; \ 197 info.si_signo = signr; \
194 info.si_errno = 0; \ 198 info.si_errno = 0; \
195 info.si_code = sicode; \ 199 info.si_code = sicode; \
196 info.si_addr = (void __user *)siaddr; \ 200 info.si_addr = (void __user *)siaddr; \
197 exception_enter(regs); \ 201 prev_state = exception_enter(); \
198 if (notify_die(DIE_TRAP, str, regs, error_code, \ 202 if (notify_die(DIE_TRAP, str, regs, error_code, \
199 trapnr, signr) == NOTIFY_STOP) { \ 203 trapnr, signr) == NOTIFY_STOP) { \
200 exception_exit(regs); \ 204 exception_exit(prev_state); \
201 return; \ 205 return; \
202 } \ 206 } \
203 conditional_sti(regs); \ 207 conditional_sti(regs); \
204 do_trap(trapnr, signr, str, regs, error_code, &info); \ 208 do_trap(trapnr, signr, str, regs, error_code, &info); \
205 exception_exit(regs); \ 209 exception_exit(prev_state); \
206} 210}
207 211
208DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV, 212DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
@@ -225,14 +229,16 @@ DO_ERROR_INFO(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check,
225/* Runs on IST stack */ 229/* Runs on IST stack */
226dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) 230dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
227{ 231{
228 exception_enter(regs); 232 enum ctx_state prev_state;
233
234 prev_state = exception_enter();
229 if (notify_die(DIE_TRAP, "stack segment", regs, error_code, 235 if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
230 X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) { 236 X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) {
231 preempt_conditional_sti(regs); 237 preempt_conditional_sti(regs);
232 do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL); 238 do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
233 preempt_conditional_cli(regs); 239 preempt_conditional_cli(regs);
234 } 240 }
235 exception_exit(regs); 241 exception_exit(prev_state);
236} 242}
237 243
238dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) 244dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
@@ -240,7 +246,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
240 static const char str[] = "double fault"; 246 static const char str[] = "double fault";
241 struct task_struct *tsk = current; 247 struct task_struct *tsk = current;
242 248
243 exception_enter(regs); 249 exception_enter();
244 /* Return not checked because double check cannot be ignored */ 250 /* Return not checked because double check cannot be ignored */
245 notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV); 251 notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
246 252
@@ -260,8 +266,9 @@ dotraplinkage void __kprobes
260do_general_protection(struct pt_regs *regs, long error_code) 266do_general_protection(struct pt_regs *regs, long error_code)
261{ 267{
262 struct task_struct *tsk; 268 struct task_struct *tsk;
269 enum ctx_state prev_state;
263 270
264 exception_enter(regs); 271 prev_state = exception_enter();
265 conditional_sti(regs); 272 conditional_sti(regs);
266 273
267#ifdef CONFIG_X86_32 274#ifdef CONFIG_X86_32
@@ -299,12 +306,14 @@ do_general_protection(struct pt_regs *regs, long error_code)
299 306
300 force_sig(SIGSEGV, tsk); 307 force_sig(SIGSEGV, tsk);
301exit: 308exit:
302 exception_exit(regs); 309 exception_exit(prev_state);
303} 310}
304 311
305/* May run on IST stack. */ 312/* May run on IST stack. */
306dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code) 313dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code)
307{ 314{
315 enum ctx_state prev_state;
316
308#ifdef CONFIG_DYNAMIC_FTRACE 317#ifdef CONFIG_DYNAMIC_FTRACE
309 /* 318 /*
310 * ftrace must be first, everything else may cause a recursive crash. 319 * ftrace must be first, everything else may cause a recursive crash.
@@ -314,7 +323,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
314 ftrace_int3_handler(regs)) 323 ftrace_int3_handler(regs))
315 return; 324 return;
316#endif 325#endif
317 exception_enter(regs); 326 prev_state = exception_enter();
318#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP 327#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
319 if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, 328 if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
320 SIGTRAP) == NOTIFY_STOP) 329 SIGTRAP) == NOTIFY_STOP)
@@ -335,7 +344,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
335 preempt_conditional_cli(regs); 344 preempt_conditional_cli(regs);
336 debug_stack_usage_dec(); 345 debug_stack_usage_dec();
337exit: 346exit:
338 exception_exit(regs); 347 exception_exit(prev_state);
339} 348}
340 349
341#ifdef CONFIG_X86_64 350#ifdef CONFIG_X86_64
@@ -392,11 +401,12 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
392dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) 401dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
393{ 402{
394 struct task_struct *tsk = current; 403 struct task_struct *tsk = current;
404 enum ctx_state prev_state;
395 int user_icebp = 0; 405 int user_icebp = 0;
396 unsigned long dr6; 406 unsigned long dr6;
397 int si_code; 407 int si_code;
398 408
399 exception_enter(regs); 409 prev_state = exception_enter();
400 410
401 get_debugreg(dr6, 6); 411 get_debugreg(dr6, 6);
402 412
@@ -466,7 +476,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
466 debug_stack_usage_dec(); 476 debug_stack_usage_dec();
467 477
468exit: 478exit:
469 exception_exit(regs); 479 exception_exit(prev_state);
470} 480}
471 481
472/* 482/*
@@ -560,17 +570,21 @@ void math_error(struct pt_regs *regs, int error_code, int trapnr)
560 570
561dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) 571dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
562{ 572{
563 exception_enter(regs); 573 enum ctx_state prev_state;
574
575 prev_state = exception_enter();
564 math_error(regs, error_code, X86_TRAP_MF); 576 math_error(regs, error_code, X86_TRAP_MF);
565 exception_exit(regs); 577 exception_exit(prev_state);
566} 578}
567 579
568dotraplinkage void 580dotraplinkage void
569do_simd_coprocessor_error(struct pt_regs *regs, long error_code) 581do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
570{ 582{
571 exception_enter(regs); 583 enum ctx_state prev_state;
584
585 prev_state = exception_enter();
572 math_error(regs, error_code, X86_TRAP_XF); 586 math_error(regs, error_code, X86_TRAP_XF);
573 exception_exit(regs); 587 exception_exit(prev_state);
574} 588}
575 589
576dotraplinkage void 590dotraplinkage void
@@ -638,7 +652,9 @@ EXPORT_SYMBOL_GPL(math_state_restore);
638dotraplinkage void __kprobes 652dotraplinkage void __kprobes
639do_device_not_available(struct pt_regs *regs, long error_code) 653do_device_not_available(struct pt_regs *regs, long error_code)
640{ 654{
641 exception_enter(regs); 655 enum ctx_state prev_state;
656
657 prev_state = exception_enter();
642 BUG_ON(use_eager_fpu()); 658 BUG_ON(use_eager_fpu());
643 659
644#ifdef CONFIG_MATH_EMULATION 660#ifdef CONFIG_MATH_EMULATION
@@ -649,7 +665,7 @@ do_device_not_available(struct pt_regs *regs, long error_code)
649 665
650 info.regs = regs; 666 info.regs = regs;
651 math_emulate(&info); 667 math_emulate(&info);
652 exception_exit(regs); 668 exception_exit(prev_state);
653 return; 669 return;
654 } 670 }
655#endif 671#endif
@@ -657,15 +673,16 @@ do_device_not_available(struct pt_regs *regs, long error_code)
657#ifdef CONFIG_X86_32 673#ifdef CONFIG_X86_32
658 conditional_sti(regs); 674 conditional_sti(regs);
659#endif 675#endif
660 exception_exit(regs); 676 exception_exit(prev_state);
661} 677}
662 678
663#ifdef CONFIG_X86_32 679#ifdef CONFIG_X86_32
664dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) 680dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
665{ 681{
666 siginfo_t info; 682 siginfo_t info;
683 enum ctx_state prev_state;
667 684
668 exception_enter(regs); 685 prev_state = exception_enter();
669 local_irq_enable(); 686 local_irq_enable();
670 687
671 info.si_signo = SIGILL; 688 info.si_signo = SIGILL;
@@ -677,7 +694,7 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
677 do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code, 694 do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
678 &info); 695 &info);
679 } 696 }
680 exception_exit(regs); 697 exception_exit(prev_state);
681} 698}
682#endif 699#endif
683 700
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index f946e6ce3315..fa8c02de0d25 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -1222,7 +1222,9 @@ good_area:
1222dotraplinkage void __kprobes 1222dotraplinkage void __kprobes
1223do_page_fault(struct pt_regs *regs, unsigned long error_code) 1223do_page_fault(struct pt_regs *regs, unsigned long error_code)
1224{ 1224{
1225 exception_enter(regs); 1225 enum ctx_state prev_state;
1226
1227 prev_state = exception_enter();
1226 __do_page_fault(regs, error_code); 1228 __do_page_fault(regs, error_code);
1227 exception_exit(regs); 1229 exception_exit(prev_state);
1228} 1230}
diff --git a/include/linux/context_tracking.h b/include/linux/context_tracking.h
index 5a69273e93e6..365f4a61bf04 100644
--- a/include/linux/context_tracking.h
+++ b/include/linux/context_tracking.h
@@ -5,7 +5,6 @@
5#include <linux/percpu.h> 5#include <linux/percpu.h>
6#include <asm/ptrace.h> 6#include <asm/ptrace.h>
7 7
8#ifdef CONFIG_CONTEXT_TRACKING
9struct context_tracking { 8struct context_tracking {
10 /* 9 /*
11 * When active is false, probes are unset in order 10 * When active is false, probes are unset in order
@@ -14,12 +13,13 @@ struct context_tracking {
14 * may be further optimized using static keys. 13 * may be further optimized using static keys.
15 */ 14 */
16 bool active; 15 bool active;
17 enum { 16 enum ctx_state {
18 IN_KERNEL = 0, 17 IN_KERNEL = 0,
19 IN_USER, 18 IN_USER,
20 } state; 19 } state;
21}; 20};
22 21
22#ifdef CONFIG_CONTEXT_TRACKING
23DECLARE_PER_CPU(struct context_tracking, context_tracking); 23DECLARE_PER_CPU(struct context_tracking, context_tracking);
24 24
25static inline bool context_tracking_in_user(void) 25static inline bool context_tracking_in_user(void)
@@ -35,14 +35,19 @@ static inline bool context_tracking_active(void)
35extern void user_enter(void); 35extern void user_enter(void);
36extern void user_exit(void); 36extern void user_exit(void);
37 37
38static inline void exception_enter(struct pt_regs *regs) 38static inline enum ctx_state exception_enter(void)
39{ 39{
40 enum ctx_state prev_ctx;
41
42 prev_ctx = this_cpu_read(context_tracking.state);
40 user_exit(); 43 user_exit();
44
45 return prev_ctx;
41} 46}
42 47
43static inline void exception_exit(struct pt_regs *regs) 48static inline void exception_exit(enum ctx_state prev_ctx)
44{ 49{
45 if (user_mode(regs)) 50 if (prev_ctx == IN_USER)
46 user_enter(); 51 user_enter();
47} 52}
48 53
@@ -52,8 +57,8 @@ extern void context_tracking_task_switch(struct task_struct *prev,
52static inline bool context_tracking_in_user(void) { return false; } 57static inline bool context_tracking_in_user(void) { return false; }
53static inline void user_enter(void) { } 58static inline void user_enter(void) { }
54static inline void user_exit(void) { } 59static inline void user_exit(void) { }
55static inline void exception_enter(struct pt_regs *regs) { } 60static inline enum ctx_state exception_enter(void) { return 0; }
56static inline void exception_exit(struct pt_regs *regs) { } 61static inline void exception_exit(enum ctx_state prev_ctx) { }
57static inline void context_tracking_task_switch(struct task_struct *prev, 62static inline void context_tracking_task_switch(struct task_struct *prev,
58 struct task_struct *next) { } 63 struct task_struct *next) { }
59#endif /* !CONFIG_CONTEXT_TRACKING */ 64#endif /* !CONFIG_CONTEXT_TRACKING */