diff options
-rw-r--r-- | arch/x86/kernel/kvm.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/traps.c | 65 | ||||
-rw-r--r-- | arch/x86/mm/fault.c | 6 | ||||
-rw-r--r-- | include/linux/context_tracking.h | 19 |
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); | |||
254 | dotraplinkage void __kprobes | 254 | dotraplinkage void __kprobes |
255 | do_async_page_fault(struct pt_regs *regs, unsigned long error_code) | 255 | do_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) \ |
176 | dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ | 176 | dotraplinkage 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) \ |
190 | dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ | 192 | dotraplinkage 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 | ||
208 | DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV, | 212 | DO_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 */ |
226 | dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) | 230 | dotraplinkage 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 | ||
238 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) | 244 | dotraplinkage 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 | |||
260 | do_general_protection(struct pt_regs *regs, long error_code) | 266 | do_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); |
301 | exit: | 308 | exit: |
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. */ |
306 | dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code) | 313 | dotraplinkage 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(); |
337 | exit: | 346 | exit: |
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) | |||
392 | dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | 401 | dotraplinkage 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 | ||
468 | exit: | 478 | exit: |
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 | ||
561 | dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) | 571 | dotraplinkage 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 | ||
568 | dotraplinkage void | 580 | dotraplinkage void |
569 | do_simd_coprocessor_error(struct pt_regs *regs, long error_code) | 581 | do_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 | ||
576 | dotraplinkage void | 590 | dotraplinkage void |
@@ -638,7 +652,9 @@ EXPORT_SYMBOL_GPL(math_state_restore); | |||
638 | dotraplinkage void __kprobes | 652 | dotraplinkage void __kprobes |
639 | do_device_not_available(struct pt_regs *regs, long error_code) | 653 | do_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 |
664 | dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) | 680 | dotraplinkage 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: | |||
1222 | dotraplinkage void __kprobes | 1222 | dotraplinkage void __kprobes |
1223 | do_page_fault(struct pt_regs *regs, unsigned long error_code) | 1223 | do_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 | ||
9 | struct context_tracking { | 8 | struct 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 | ||
23 | DECLARE_PER_CPU(struct context_tracking, context_tracking); | 23 | DECLARE_PER_CPU(struct context_tracking, context_tracking); |
24 | 24 | ||
25 | static inline bool context_tracking_in_user(void) | 25 | static inline bool context_tracking_in_user(void) |
@@ -35,14 +35,19 @@ static inline bool context_tracking_active(void) | |||
35 | extern void user_enter(void); | 35 | extern void user_enter(void); |
36 | extern void user_exit(void); | 36 | extern void user_exit(void); |
37 | 37 | ||
38 | static inline void exception_enter(struct pt_regs *regs) | 38 | static 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 | ||
43 | static inline void exception_exit(struct pt_regs *regs) | 48 | static 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, | |||
52 | static inline bool context_tracking_in_user(void) { return false; } | 57 | static inline bool context_tracking_in_user(void) { return false; } |
53 | static inline void user_enter(void) { } | 58 | static inline void user_enter(void) { } |
54 | static inline void user_exit(void) { } | 59 | static inline void user_exit(void) { } |
55 | static inline void exception_enter(struct pt_regs *regs) { } | 60 | static inline enum ctx_state exception_enter(void) { return 0; } |
56 | static inline void exception_exit(struct pt_regs *regs) { } | 61 | static inline void exception_exit(enum ctx_state prev_ctx) { } |
57 | static inline void context_tracking_task_switch(struct task_struct *prev, | 62 | static 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 */ |