diff options
author | Andrea Arcangeli <andrea@cpushare.com> | 2007-07-16 02:41:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 12:05:50 -0400 |
commit | cf99abace7e07dd8491e7093a9a9ef11d48838ed (patch) | |
tree | 3b7cfd7c76c2c43e6ae3fdaaff3a50a752072424 | |
parent | 1d9d02feeee89e9132034d504c9a45eeaf618a3d (diff) |
make seccomp zerocost in schedule
This follows a suggestion from Chuck Ebbert on how to make seccomp
absolutely zerocost in schedule too. The only remaining footprint of
seccomp is in terms of the bzImage size that becomes a few bytes (perhaps
even a few kbytes) larger, measure it if you care in the embedded.
Signed-off-by: Andrea Arcangeli <andrea@cpushare.com>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/i386/kernel/process.c | 73 | ||||
-rw-r--r-- | include/asm-i386/processor.h | 4 | ||||
-rw-r--r-- | include/asm-i386/thread_info.h | 5 | ||||
-rw-r--r-- | include/linux/seccomp.h | 10 | ||||
-rw-r--r-- | kernel/seccomp.c | 3 |
5 files changed, 50 insertions, 45 deletions
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 06dfa65ad180..6c49acb96982 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c | |||
@@ -538,8 +538,31 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) | |||
538 | return 1; | 538 | return 1; |
539 | } | 539 | } |
540 | 540 | ||
541 | static noinline void __switch_to_xtra(struct task_struct *next_p, | 541 | #ifdef CONFIG_SECCOMP |
542 | struct tss_struct *tss) | 542 | void hard_disable_TSC(void) |
543 | { | ||
544 | write_cr4(read_cr4() | X86_CR4_TSD); | ||
545 | } | ||
546 | void disable_TSC(void) | ||
547 | { | ||
548 | preempt_disable(); | ||
549 | if (!test_and_set_thread_flag(TIF_NOTSC)) | ||
550 | /* | ||
551 | * Must flip the CPU state synchronously with | ||
552 | * TIF_NOTSC in the current running context. | ||
553 | */ | ||
554 | hard_disable_TSC(); | ||
555 | preempt_enable(); | ||
556 | } | ||
557 | void hard_enable_TSC(void) | ||
558 | { | ||
559 | write_cr4(read_cr4() & ~X86_CR4_TSD); | ||
560 | } | ||
561 | #endif /* CONFIG_SECCOMP */ | ||
562 | |||
563 | static noinline void | ||
564 | __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, | ||
565 | struct tss_struct *tss) | ||
543 | { | 566 | { |
544 | struct thread_struct *next; | 567 | struct thread_struct *next; |
545 | 568 | ||
@@ -555,6 +578,17 @@ static noinline void __switch_to_xtra(struct task_struct *next_p, | |||
555 | set_debugreg(next->debugreg[7], 7); | 578 | set_debugreg(next->debugreg[7], 7); |
556 | } | 579 | } |
557 | 580 | ||
581 | #ifdef CONFIG_SECCOMP | ||
582 | if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^ | ||
583 | test_tsk_thread_flag(next_p, TIF_NOTSC)) { | ||
584 | /* prev and next are different */ | ||
585 | if (test_tsk_thread_flag(next_p, TIF_NOTSC)) | ||
586 | hard_disable_TSC(); | ||
587 | else | ||
588 | hard_enable_TSC(); | ||
589 | } | ||
590 | #endif | ||
591 | |||
558 | if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { | 592 | if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { |
559 | /* | 593 | /* |
560 | * Disable the bitmap via an invalid offset. We still cache | 594 | * Disable the bitmap via an invalid offset. We still cache |
@@ -586,33 +620,6 @@ static noinline void __switch_to_xtra(struct task_struct *next_p, | |||
586 | } | 620 | } |
587 | 621 | ||
588 | /* | 622 | /* |
589 | * This function selects if the context switch from prev to next | ||
590 | * has to tweak the TSC disable bit in the cr4. | ||
591 | */ | ||
592 | static inline void disable_tsc(struct task_struct *prev_p, | ||
593 | struct task_struct *next_p) | ||
594 | { | ||
595 | struct thread_info *prev, *next; | ||
596 | |||
597 | /* | ||
598 | * gcc should eliminate the ->thread_info dereference if | ||
599 | * has_secure_computing returns 0 at compile time (SECCOMP=n). | ||
600 | */ | ||
601 | prev = task_thread_info(prev_p); | ||
602 | next = task_thread_info(next_p); | ||
603 | |||
604 | if (has_secure_computing(prev) || has_secure_computing(next)) { | ||
605 | /* slow path here */ | ||
606 | if (has_secure_computing(prev) && | ||
607 | !has_secure_computing(next)) { | ||
608 | write_cr4(read_cr4() & ~X86_CR4_TSD); | ||
609 | } else if (!has_secure_computing(prev) && | ||
610 | has_secure_computing(next)) | ||
611 | write_cr4(read_cr4() | X86_CR4_TSD); | ||
612 | } | ||
613 | } | ||
614 | |||
615 | /* | ||
616 | * switch_to(x,yn) should switch tasks from x to y. | 623 | * switch_to(x,yn) should switch tasks from x to y. |
617 | * | 624 | * |
618 | * We fsave/fwait so that an exception goes off at the right time | 625 | * We fsave/fwait so that an exception goes off at the right time |
@@ -689,11 +696,9 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas | |||
689 | /* | 696 | /* |
690 | * Now maybe handle debug registers and/or IO bitmaps | 697 | * Now maybe handle debug registers and/or IO bitmaps |
691 | */ | 698 | */ |
692 | if (unlikely((task_thread_info(next_p)->flags & _TIF_WORK_CTXSW) | 699 | if (unlikely(task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV || |
693 | || test_tsk_thread_flag(prev_p, TIF_IO_BITMAP))) | 700 | task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT)) |
694 | __switch_to_xtra(next_p, tss); | 701 | __switch_to_xtra(prev_p, next_p, tss); |
695 | |||
696 | disable_tsc(prev_p, next_p); | ||
697 | 702 | ||
698 | /* | 703 | /* |
699 | * Leave lazy mode, flushing any hypercalls made here. | 704 | * Leave lazy mode, flushing any hypercalls made here. |
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 94e0c147c165..422cffef00c9 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h | |||
@@ -228,6 +228,10 @@ extern int bootloader_type; | |||
228 | 228 | ||
229 | #define HAVE_ARCH_PICK_MMAP_LAYOUT | 229 | #define HAVE_ARCH_PICK_MMAP_LAYOUT |
230 | 230 | ||
231 | extern void hard_disable_TSC(void); | ||
232 | extern void disable_TSC(void); | ||
233 | extern void hard_enable_TSC(void); | ||
234 | |||
231 | /* | 235 | /* |
232 | * Size of io_bitmap. | 236 | * Size of io_bitmap. |
233 | */ | 237 | */ |
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h index 4cb0f91ae64f..54424e045e01 100644 --- a/include/asm-i386/thread_info.h +++ b/include/asm-i386/thread_info.h | |||
@@ -137,6 +137,7 @@ static inline struct thread_info *current_thread_info(void) | |||
137 | #define TIF_DEBUG 17 /* uses debug registers */ | 137 | #define TIF_DEBUG 17 /* uses debug registers */ |
138 | #define TIF_IO_BITMAP 18 /* uses I/O bitmap */ | 138 | #define TIF_IO_BITMAP 18 /* uses I/O bitmap */ |
139 | #define TIF_FREEZE 19 /* is freezing for suspend */ | 139 | #define TIF_FREEZE 19 /* is freezing for suspend */ |
140 | #define TIF_NOTSC 20 /* TSC is not accessible in userland */ | ||
140 | 141 | ||
141 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) | 142 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) |
142 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) | 143 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) |
@@ -151,6 +152,7 @@ static inline struct thread_info *current_thread_info(void) | |||
151 | #define _TIF_DEBUG (1<<TIF_DEBUG) | 152 | #define _TIF_DEBUG (1<<TIF_DEBUG) |
152 | #define _TIF_IO_BITMAP (1<<TIF_IO_BITMAP) | 153 | #define _TIF_IO_BITMAP (1<<TIF_IO_BITMAP) |
153 | #define _TIF_FREEZE (1<<TIF_FREEZE) | 154 | #define _TIF_FREEZE (1<<TIF_FREEZE) |
155 | #define _TIF_NOTSC (1<<TIF_NOTSC) | ||
154 | 156 | ||
155 | /* work to do on interrupt/exception return */ | 157 | /* work to do on interrupt/exception return */ |
156 | #define _TIF_WORK_MASK \ | 158 | #define _TIF_WORK_MASK \ |
@@ -160,7 +162,8 @@ static inline struct thread_info *current_thread_info(void) | |||
160 | #define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP) | 162 | #define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP) |
161 | 163 | ||
162 | /* flags to check in __switch_to() */ | 164 | /* flags to check in __switch_to() */ |
163 | #define _TIF_WORK_CTXSW (_TIF_DEBUG|_TIF_IO_BITMAP) | 165 | #define _TIF_WORK_CTXSW_NEXT (_TIF_IO_BITMAP | _TIF_NOTSC | _TIF_DEBUG) |
166 | #define _TIF_WORK_CTXSW_PREV (_TIF_IO_BITMAP | _TIF_NOTSC) | ||
164 | 167 | ||
165 | /* | 168 | /* |
166 | * Thread-synchronous status. | 169 | * Thread-synchronous status. |
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index d708974dbfe3..262a8dccfa81 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h | |||
@@ -16,11 +16,6 @@ static inline void secure_computing(int this_syscall) | |||
16 | __secure_computing(this_syscall); | 16 | __secure_computing(this_syscall); |
17 | } | 17 | } |
18 | 18 | ||
19 | static inline int has_secure_computing(struct thread_info *ti) | ||
20 | { | ||
21 | return unlikely(test_ti_thread_flag(ti, TIF_SECCOMP)); | ||
22 | } | ||
23 | |||
24 | extern long prctl_get_seccomp(void); | 19 | extern long prctl_get_seccomp(void); |
25 | extern long prctl_set_seccomp(unsigned long); | 20 | extern long prctl_set_seccomp(unsigned long); |
26 | 21 | ||
@@ -29,11 +24,6 @@ extern long prctl_set_seccomp(unsigned long); | |||
29 | typedef struct { } seccomp_t; | 24 | typedef struct { } seccomp_t; |
30 | 25 | ||
31 | #define secure_computing(x) do { } while (0) | 26 | #define secure_computing(x) do { } while (0) |
32 | /* static inline to preserve typechecking */ | ||
33 | static inline int has_secure_computing(struct thread_info *ti) | ||
34 | { | ||
35 | return 0; | ||
36 | } | ||
37 | 27 | ||
38 | static inline long prctl_get_seccomp(void) | 28 | static inline long prctl_get_seccomp(void) |
39 | { | 29 | { |
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 1dfa8a509726..ad64fcb731f2 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -74,6 +74,9 @@ long prctl_set_seccomp(unsigned long seccomp_mode) | |||
74 | if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) { | 74 | if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) { |
75 | current->seccomp.mode = seccomp_mode; | 75 | current->seccomp.mode = seccomp_mode; |
76 | set_thread_flag(TIF_SECCOMP); | 76 | set_thread_flag(TIF_SECCOMP); |
77 | #ifdef TIF_NOTSC | ||
78 | disable_TSC(); | ||
79 | #endif | ||
77 | ret = 0; | 80 | ret = 0; |
78 | } | 81 | } |
79 | 82 | ||