diff options
author | Andy Lutomirski <luto@amacapital.net> | 2014-11-22 21:00:32 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-23 16:56:19 -0500 |
commit | 6f442be2fb22be02cafa606f1769fa1e6f894441 (patch) | |
tree | 1173ca6feb0cdda19b5383e713e2f19152d88940 | |
parent | af726f21ed8af2cdaa4e93098dc211521218ae65 (diff) |
x86_64, traps: Stop using IST for #SS
On a 32-bit kernel, this has no effect, since there are no IST stacks.
On a 64-bit kernel, #SS can only happen in user code, on a failed iret
to user space, a canonical violation on access via RSP or RBP, or a
genuine stack segment violation in 32-bit kernel code. The first two
cases don't need IST, and the latter two cases are unlikely fatal bugs,
and promoting them to double faults would be fine.
This fixes a bug in which the espfix64 code mishandles a stack segment
violation.
This saves 4k of memory per CPU and a tiny bit of code.
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/x86/include/asm/page_32_types.h | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/page_64_types.h | 11 | ||||
-rw-r--r-- | arch/x86/include/asm/traps.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/dumpstack_64.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/entry_64.S | 2 | ||||
-rw-r--r-- | arch/x86/kernel/traps.c | 18 |
6 files changed, 8 insertions, 26 deletions
diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h index f48b17df4224..3a52ee0e726d 100644 --- a/arch/x86/include/asm/page_32_types.h +++ b/arch/x86/include/asm/page_32_types.h | |||
@@ -20,7 +20,6 @@ | |||
20 | #define THREAD_SIZE_ORDER 1 | 20 | #define THREAD_SIZE_ORDER 1 |
21 | #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) | 21 | #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) |
22 | 22 | ||
23 | #define STACKFAULT_STACK 0 | ||
24 | #define DOUBLEFAULT_STACK 1 | 23 | #define DOUBLEFAULT_STACK 1 |
25 | #define NMI_STACK 0 | 24 | #define NMI_STACK 0 |
26 | #define DEBUG_STACK 0 | 25 | #define DEBUG_STACK 0 |
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h index 678205195ae1..75450b2c7be4 100644 --- a/arch/x86/include/asm/page_64_types.h +++ b/arch/x86/include/asm/page_64_types.h | |||
@@ -14,12 +14,11 @@ | |||
14 | #define IRQ_STACK_ORDER 2 | 14 | #define IRQ_STACK_ORDER 2 |
15 | #define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER) | 15 | #define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER) |
16 | 16 | ||
17 | #define STACKFAULT_STACK 1 | 17 | #define DOUBLEFAULT_STACK 1 |
18 | #define DOUBLEFAULT_STACK 2 | 18 | #define NMI_STACK 2 |
19 | #define NMI_STACK 3 | 19 | #define DEBUG_STACK 3 |
20 | #define DEBUG_STACK 4 | 20 | #define MCE_STACK 4 |
21 | #define MCE_STACK 5 | 21 | #define N_EXCEPTION_STACKS 4 /* hw limit: 7 */ |
22 | #define N_EXCEPTION_STACKS 5 /* hw limit: 7 */ | ||
23 | 22 | ||
24 | #define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT) | 23 | #define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT) |
25 | #define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1)) | 24 | #define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1)) |
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index bc8352e7010a..707adc6549d8 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h | |||
@@ -39,6 +39,7 @@ asmlinkage void simd_coprocessor_error(void); | |||
39 | 39 | ||
40 | #ifdef CONFIG_TRACING | 40 | #ifdef CONFIG_TRACING |
41 | asmlinkage void trace_page_fault(void); | 41 | asmlinkage void trace_page_fault(void); |
42 | #define trace_stack_segment stack_segment | ||
42 | #define trace_divide_error divide_error | 43 | #define trace_divide_error divide_error |
43 | #define trace_bounds bounds | 44 | #define trace_bounds bounds |
44 | #define trace_invalid_op invalid_op | 45 | #define trace_invalid_op invalid_op |
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 1abcb50b48ae..ff86f19b5758 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c | |||
@@ -24,7 +24,6 @@ static char x86_stack_ids[][8] = { | |||
24 | [ DEBUG_STACK-1 ] = "#DB", | 24 | [ DEBUG_STACK-1 ] = "#DB", |
25 | [ NMI_STACK-1 ] = "NMI", | 25 | [ NMI_STACK-1 ] = "NMI", |
26 | [ DOUBLEFAULT_STACK-1 ] = "#DF", | 26 | [ DOUBLEFAULT_STACK-1 ] = "#DF", |
27 | [ STACKFAULT_STACK-1 ] = "#SS", | ||
28 | [ MCE_STACK-1 ] = "#MC", | 27 | [ MCE_STACK-1 ] = "#MC", |
29 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | 28 | #if DEBUG_STKSZ > EXCEPTION_STKSZ |
30 | [ N_EXCEPTION_STACKS ... | 29 | [ N_EXCEPTION_STACKS ... |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index a4dc8de7c4be..49a0c1781253 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -1259,7 +1259,7 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \ | |||
1259 | 1259 | ||
1260 | idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK | 1260 | idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK |
1261 | idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK | 1261 | idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK |
1262 | idtentry stack_segment do_stack_segment has_error_code=1 paranoid=1 | 1262 | idtentry stack_segment do_stack_segment has_error_code=1 |
1263 | #ifdef CONFIG_XEN | 1263 | #ifdef CONFIG_XEN |
1264 | idtentry xen_debug do_debug has_error_code=0 | 1264 | idtentry xen_debug do_debug has_error_code=0 |
1265 | idtentry xen_int3 do_int3 has_error_code=0 | 1265 | idtentry xen_int3 do_int3 has_error_code=0 |
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 819662746e23..48035e9cdde9 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
@@ -233,27 +233,11 @@ DO_ERROR(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op) | |||
233 | DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun) | 233 | DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun) |
234 | DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS) | 234 | DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS) |
235 | DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present) | 235 | DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present) |
236 | #ifdef CONFIG_X86_32 | ||
237 | DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment) | 236 | DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment) |
238 | #endif | ||
239 | DO_ERROR(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check) | 237 | DO_ERROR(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check) |
240 | 238 | ||
241 | #ifdef CONFIG_X86_64 | 239 | #ifdef CONFIG_X86_64 |
242 | /* Runs on IST stack */ | 240 | /* Runs on IST stack */ |
243 | dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) | ||
244 | { | ||
245 | enum ctx_state prev_state; | ||
246 | |||
247 | prev_state = exception_enter(); | ||
248 | if (notify_die(DIE_TRAP, "stack segment", regs, error_code, | ||
249 | X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) { | ||
250 | preempt_conditional_sti(regs); | ||
251 | do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL); | ||
252 | preempt_conditional_cli(regs); | ||
253 | } | ||
254 | exception_exit(prev_state); | ||
255 | } | ||
256 | |||
257 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) | 241 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) |
258 | { | 242 | { |
259 | static const char str[] = "double fault"; | 243 | static const char str[] = "double fault"; |
@@ -802,7 +786,7 @@ void __init trap_init(void) | |||
802 | set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun); | 786 | set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun); |
803 | set_intr_gate(X86_TRAP_TS, invalid_TSS); | 787 | set_intr_gate(X86_TRAP_TS, invalid_TSS); |
804 | set_intr_gate(X86_TRAP_NP, segment_not_present); | 788 | set_intr_gate(X86_TRAP_NP, segment_not_present); |
805 | set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK); | 789 | set_intr_gate(X86_TRAP_SS, stack_segment); |
806 | set_intr_gate(X86_TRAP_GP, general_protection); | 790 | set_intr_gate(X86_TRAP_GP, general_protection); |
807 | set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug); | 791 | set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug); |
808 | set_intr_gate(X86_TRAP_MF, coprocessor_error); | 792 | set_intr_gate(X86_TRAP_MF, coprocessor_error); |