diff options
-rw-r--r-- | arch/i386/kernel/process.c | 29 | ||||
-rw-r--r-- | arch/x86_64/kernel/process.c | 29 | ||||
-rw-r--r-- | include/asm-i386/tlbflush.h | 12 | ||||
-rw-r--r-- | include/asm-x86_64/tlbflush.h | 12 | ||||
-rw-r--r-- | include/linux/seccomp.h | 10 |
5 files changed, 82 insertions, 10 deletions
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 5f8cfa6b7940..ba243a4cc119 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c | |||
@@ -617,6 +617,33 @@ handle_io_bitmap(struct thread_struct *next, struct tss_struct *tss) | |||
617 | } | 617 | } |
618 | 618 | ||
619 | /* | 619 | /* |
620 | * This function selects if the context switch from prev to next | ||
621 | * has to tweak the TSC disable bit in the cr4. | ||
622 | */ | ||
623 | static inline void disable_tsc(struct task_struct *prev_p, | ||
624 | struct task_struct *next_p) | ||
625 | { | ||
626 | struct thread_info *prev, *next; | ||
627 | |||
628 | /* | ||
629 | * gcc should eliminate the ->thread_info dereference if | ||
630 | * has_secure_computing returns 0 at compile time (SECCOMP=n). | ||
631 | */ | ||
632 | prev = prev_p->thread_info; | ||
633 | next = next_p->thread_info; | ||
634 | |||
635 | if (has_secure_computing(prev) || has_secure_computing(next)) { | ||
636 | /* slow path here */ | ||
637 | if (has_secure_computing(prev) && | ||
638 | !has_secure_computing(next)) { | ||
639 | write_cr4(read_cr4() & ~X86_CR4_TSD); | ||
640 | } else if (!has_secure_computing(prev) && | ||
641 | has_secure_computing(next)) | ||
642 | write_cr4(read_cr4() | X86_CR4_TSD); | ||
643 | } | ||
644 | } | ||
645 | |||
646 | /* | ||
620 | * switch_to(x,yn) should switch tasks from x to y. | 647 | * switch_to(x,yn) should switch tasks from x to y. |
621 | * | 648 | * |
622 | * We fsave/fwait so that an exception goes off at the right time | 649 | * We fsave/fwait so that an exception goes off at the right time |
@@ -695,6 +722,8 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas | |||
695 | if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) | 722 | if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) |
696 | handle_io_bitmap(next, tss); | 723 | handle_io_bitmap(next, tss); |
697 | 724 | ||
725 | disable_tsc(prev_p, next_p); | ||
726 | |||
698 | return prev_p; | 727 | return prev_p; |
699 | } | 728 | } |
700 | 729 | ||
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 1d91271796e5..7577f9d7a75d 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c | |||
@@ -482,6 +482,33 @@ out: | |||
482 | } | 482 | } |
483 | 483 | ||
484 | /* | 484 | /* |
485 | * This function selects if the context switch from prev to next | ||
486 | * has to tweak the TSC disable bit in the cr4. | ||
487 | */ | ||
488 | static inline void disable_tsc(struct task_struct *prev_p, | ||
489 | struct task_struct *next_p) | ||
490 | { | ||
491 | struct thread_info *prev, *next; | ||
492 | |||
493 | /* | ||
494 | * gcc should eliminate the ->thread_info dereference if | ||
495 | * has_secure_computing returns 0 at compile time (SECCOMP=n). | ||
496 | */ | ||
497 | prev = prev_p->thread_info; | ||
498 | next = next_p->thread_info; | ||
499 | |||
500 | if (has_secure_computing(prev) || has_secure_computing(next)) { | ||
501 | /* slow path here */ | ||
502 | if (has_secure_computing(prev) && | ||
503 | !has_secure_computing(next)) { | ||
504 | write_cr4(read_cr4() & ~X86_CR4_TSD); | ||
505 | } else if (!has_secure_computing(prev) && | ||
506 | has_secure_computing(next)) | ||
507 | write_cr4(read_cr4() | X86_CR4_TSD); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | /* | ||
485 | * This special macro can be used to load a debugging register | 512 | * This special macro can be used to load a debugging register |
486 | */ | 513 | */ |
487 | #define loaddebug(thread,r) set_debug(thread->debugreg ## r, r) | 514 | #define loaddebug(thread,r) set_debug(thread->debugreg ## r, r) |
@@ -599,6 +626,8 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct * | |||
599 | } | 626 | } |
600 | } | 627 | } |
601 | 628 | ||
629 | disable_tsc(prev_p, next_p); | ||
630 | |||
602 | return prev_p; | 631 | return prev_p; |
603 | } | 632 | } |
604 | 633 | ||
diff --git a/include/asm-i386/tlbflush.h b/include/asm-i386/tlbflush.h index f22fab0cea26..ab216e1370ef 100644 --- a/include/asm-i386/tlbflush.h +++ b/include/asm-i386/tlbflush.h | |||
@@ -22,16 +22,18 @@ | |||
22 | */ | 22 | */ |
23 | #define __flush_tlb_global() \ | 23 | #define __flush_tlb_global() \ |
24 | do { \ | 24 | do { \ |
25 | unsigned int tmpreg; \ | 25 | unsigned int tmpreg, cr4, cr4_orig; \ |
26 | \ | 26 | \ |
27 | __asm__ __volatile__( \ | 27 | __asm__ __volatile__( \ |
28 | "movl %1, %%cr4; # turn off PGE \n" \ | 28 | "movl %%cr4, %2; # turn off PGE \n" \ |
29 | "movl %2, %1; \n" \ | ||
30 | "andl %3, %1; \n" \ | ||
31 | "movl %1, %%cr4; \n" \ | ||
29 | "movl %%cr3, %0; \n" \ | 32 | "movl %%cr3, %0; \n" \ |
30 | "movl %0, %%cr3; # flush TLB \n" \ | 33 | "movl %0, %%cr3; # flush TLB \n" \ |
31 | "movl %2, %%cr4; # turn PGE back on \n" \ | 34 | "movl %2, %%cr4; # turn PGE back on \n" \ |
32 | : "=&r" (tmpreg) \ | 35 | : "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig) \ |
33 | : "r" (mmu_cr4_features & ~X86_CR4_PGE), \ | 36 | : "i" (~X86_CR4_PGE) \ |
34 | "r" (mmu_cr4_features) \ | ||
35 | : "memory"); \ | 37 | : "memory"); \ |
36 | } while (0) | 38 | } while (0) |
37 | 39 | ||
diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86_64/tlbflush.h index 2e811ac262af..061742382520 100644 --- a/include/asm-x86_64/tlbflush.h +++ b/include/asm-x86_64/tlbflush.h | |||
@@ -22,16 +22,18 @@ | |||
22 | */ | 22 | */ |
23 | #define __flush_tlb_global() \ | 23 | #define __flush_tlb_global() \ |
24 | do { \ | 24 | do { \ |
25 | unsigned long tmpreg; \ | 25 | unsigned long tmpreg, cr4, cr4_orig; \ |
26 | \ | 26 | \ |
27 | __asm__ __volatile__( \ | 27 | __asm__ __volatile__( \ |
28 | "movq %1, %%cr4; # turn off PGE \n" \ | 28 | "movq %%cr4, %2; # turn off PGE \n" \ |
29 | "movq %2, %1; \n" \ | ||
30 | "andq %3, %1; \n" \ | ||
31 | "movq %1, %%cr4; \n" \ | ||
29 | "movq %%cr3, %0; # flush TLB \n" \ | 32 | "movq %%cr3, %0; # flush TLB \n" \ |
30 | "movq %0, %%cr3; \n" \ | 33 | "movq %0, %%cr3; \n" \ |
31 | "movq %2, %%cr4; # turn PGE back on \n" \ | 34 | "movq %2, %%cr4; # turn PGE back on \n" \ |
32 | : "=&r" (tmpreg) \ | 35 | : "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig) \ |
33 | : "r" (mmu_cr4_features & ~X86_CR4_PGE), \ | 36 | : "i" (~X86_CR4_PGE) \ |
34 | "r" (mmu_cr4_features) \ | ||
35 | : "memory"); \ | 37 | : "memory"); \ |
36 | } while (0) | 38 | } while (0) |
37 | 39 | ||
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index 3a2702bbb1d6..dc89116bb1ca 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h | |||
@@ -19,6 +19,11 @@ static inline void secure_computing(int this_syscall) | |||
19 | __secure_computing(this_syscall); | 19 | __secure_computing(this_syscall); |
20 | } | 20 | } |
21 | 21 | ||
22 | static inline int has_secure_computing(struct thread_info *ti) | ||
23 | { | ||
24 | return unlikely(test_ti_thread_flag(ti, TIF_SECCOMP)); | ||
25 | } | ||
26 | |||
22 | #else /* CONFIG_SECCOMP */ | 27 | #else /* CONFIG_SECCOMP */ |
23 | 28 | ||
24 | #if (__GNUC__ > 2) | 29 | #if (__GNUC__ > 2) |
@@ -28,6 +33,11 @@ static inline void secure_computing(int this_syscall) | |||
28 | #endif | 33 | #endif |
29 | 34 | ||
30 | #define secure_computing(x) do { } while (0) | 35 | #define secure_computing(x) do { } while (0) |
36 | /* static inline to preserve typechecking */ | ||
37 | static inline int has_secure_computing(struct thread_info *ti) | ||
38 | { | ||
39 | return 0; | ||
40 | } | ||
31 | 41 | ||
32 | #endif /* CONFIG_SECCOMP */ | 42 | #endif /* CONFIG_SECCOMP */ |
33 | 43 | ||