diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2018-02-11 05:49:44 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2018-02-13 03:04:53 -0500 |
commit | f7bafa2b05ef25eda1d9179fd930b0330cf2b7d1 (patch) | |
tree | 376d948cc86ebb186e30ec8c36bc9dfedf8e1271 | |
parent | 502af0d70843c2a9405d7ba1f79b4b0305aaf5f5 (diff) |
x86/entry/64: Interleave XOR register clearing with PUSH instructions
Same as is done for syscalls, interleave XOR with PUSH instructions
for exceptions/interrupts, in order to minimize the cost of the
additional instructions required for register clearing.
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: dan.j.williams@intel.com
Link: http://lkml.kernel.org/r/20180211104949.12992-4-linux@dominikbrodowski.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/entry/calling.h | 40 | ||||
-rw-r--r-- | arch/x86/entry/entry_64.S | 30 |
2 files changed, 40 insertions, 30 deletions
diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h index 3bda31736a7b..a05cbb81268d 100644 --- a/arch/x86/entry/calling.h +++ b/arch/x86/entry/calling.h | |||
@@ -101,44 +101,42 @@ For 32-bit we have the following conventions - kernel is built with | |||
101 | addq $-(15*8), %rsp | 101 | addq $-(15*8), %rsp |
102 | .endm | 102 | .endm |
103 | 103 | ||
104 | .macro SAVE_REGS offset=0 | 104 | .macro SAVE_AND_CLEAR_REGS offset=0 |
105 | /* | ||
106 | * Save registers and sanitize registers of values that a | ||
107 | * speculation attack might otherwise want to exploit. The | ||
108 | * lower registers are likely clobbered well before they | ||
109 | * could be put to use in a speculative execution gadget. | ||
110 | * Interleave XOR with PUSH for better uop scheduling: | ||
111 | */ | ||
105 | movq %rdi, 14*8+\offset(%rsp) | 112 | movq %rdi, 14*8+\offset(%rsp) |
106 | movq %rsi, 13*8+\offset(%rsp) | 113 | movq %rsi, 13*8+\offset(%rsp) |
107 | movq %rdx, 12*8+\offset(%rsp) | 114 | movq %rdx, 12*8+\offset(%rsp) |
108 | movq %rcx, 11*8+\offset(%rsp) | 115 | movq %rcx, 11*8+\offset(%rsp) |
109 | movq %rax, 10*8+\offset(%rsp) | 116 | movq %rax, 10*8+\offset(%rsp) |
110 | movq %r8, 9*8+\offset(%rsp) | 117 | movq %r8, 9*8+\offset(%rsp) |
118 | xorq %r8, %r8 /* nospec r8 */ | ||
111 | movq %r9, 8*8+\offset(%rsp) | 119 | movq %r9, 8*8+\offset(%rsp) |
120 | xorq %r9, %r9 /* nospec r9 */ | ||
112 | movq %r10, 7*8+\offset(%rsp) | 121 | movq %r10, 7*8+\offset(%rsp) |
122 | xorq %r10, %r10 /* nospec r10 */ | ||
113 | movq %r11, 6*8+\offset(%rsp) | 123 | movq %r11, 6*8+\offset(%rsp) |
124 | xorq %r11, %r11 /* nospec r11 */ | ||
114 | movq %rbx, 5*8+\offset(%rsp) | 125 | movq %rbx, 5*8+\offset(%rsp) |
126 | xorl %ebx, %ebx /* nospec rbx */ | ||
115 | movq %rbp, 4*8+\offset(%rsp) | 127 | movq %rbp, 4*8+\offset(%rsp) |
128 | xorl %ebp, %ebp /* nospec rbp */ | ||
116 | movq %r12, 3*8+\offset(%rsp) | 129 | movq %r12, 3*8+\offset(%rsp) |
130 | xorq %r12, %r12 /* nospec r12 */ | ||
117 | movq %r13, 2*8+\offset(%rsp) | 131 | movq %r13, 2*8+\offset(%rsp) |
132 | xorq %r13, %r13 /* nospec r13 */ | ||
118 | movq %r14, 1*8+\offset(%rsp) | 133 | movq %r14, 1*8+\offset(%rsp) |
134 | xorq %r14, %r14 /* nospec r14 */ | ||
119 | movq %r15, 0*8+\offset(%rsp) | 135 | movq %r15, 0*8+\offset(%rsp) |
136 | xorq %r15, %r15 /* nospec r15 */ | ||
120 | UNWIND_HINT_REGS offset=\offset | 137 | UNWIND_HINT_REGS offset=\offset |
121 | .endm | 138 | .endm |
122 | 139 | ||
123 | /* | ||
124 | * Sanitize registers of values that a speculation attack | ||
125 | * might otherwise want to exploit. The lower registers are | ||
126 | * likely clobbered well before they could be put to use in | ||
127 | * a speculative execution gadget: | ||
128 | */ | ||
129 | .macro CLEAR_REGS_NOSPEC | ||
130 | xorl %ebp, %ebp | ||
131 | xorl %ebx, %ebx | ||
132 | xorq %r8, %r8 | ||
133 | xorq %r9, %r9 | ||
134 | xorq %r10, %r10 | ||
135 | xorq %r11, %r11 | ||
136 | xorq %r12, %r12 | ||
137 | xorq %r13, %r13 | ||
138 | xorq %r14, %r14 | ||
139 | xorq %r15, %r15 | ||
140 | .endm | ||
141 | |||
142 | .macro POP_REGS pop_rdi=1 skip_r11rcx=0 | 140 | .macro POP_REGS pop_rdi=1 skip_r11rcx=0 |
143 | popq %r15 | 141 | popq %r15 |
144 | popq %r14 | 142 | popq %r14 |
@@ -177,7 +175,7 @@ For 32-bit we have the following conventions - kernel is built with | |||
177 | * is just setting the LSB, which makes it an invalid stack address and is also | 175 | * is just setting the LSB, which makes it an invalid stack address and is also |
178 | * a signal to the unwinder that it's a pt_regs pointer in disguise. | 176 | * a signal to the unwinder that it's a pt_regs pointer in disguise. |
179 | * | 177 | * |
180 | * NOTE: This macro must be used *after* SAVE_REGS because it corrupts | 178 | * NOTE: This macro must be used *after* SAVE_AND_CLEAR_REGS because it corrupts |
181 | * the original rbp. | 179 | * the original rbp. |
182 | */ | 180 | */ |
183 | .macro ENCODE_FRAME_POINTER ptregs_offset=0 | 181 | .macro ENCODE_FRAME_POINTER ptregs_offset=0 |
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 7351c91fb7df..07692b44800d 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S | |||
@@ -565,8 +565,7 @@ END(irq_entries_start) | |||
565 | 1: | 565 | 1: |
566 | 566 | ||
567 | ALLOC_PT_GPREGS_ON_STACK | 567 | ALLOC_PT_GPREGS_ON_STACK |
568 | SAVE_REGS | 568 | SAVE_AND_CLEAR_REGS |
569 | CLEAR_REGS_NOSPEC | ||
570 | ENCODE_FRAME_POINTER | 569 | ENCODE_FRAME_POINTER |
571 | 570 | ||
572 | testb $3, CS(%rsp) | 571 | testb $3, CS(%rsp) |
@@ -1114,8 +1113,7 @@ ENTRY(xen_failsafe_callback) | |||
1114 | UNWIND_HINT_IRET_REGS | 1113 | UNWIND_HINT_IRET_REGS |
1115 | pushq $-1 /* orig_ax = -1 => not a system call */ | 1114 | pushq $-1 /* orig_ax = -1 => not a system call */ |
1116 | ALLOC_PT_GPREGS_ON_STACK | 1115 | ALLOC_PT_GPREGS_ON_STACK |
1117 | SAVE_REGS | 1116 | SAVE_AND_CLEAR_REGS |
1118 | CLEAR_REGS_NOSPEC | ||
1119 | ENCODE_FRAME_POINTER | 1117 | ENCODE_FRAME_POINTER |
1120 | jmp error_exit | 1118 | jmp error_exit |
1121 | END(xen_failsafe_callback) | 1119 | END(xen_failsafe_callback) |
@@ -1159,8 +1157,7 @@ idtentry machine_check do_mce has_error_code=0 paranoid=1 | |||
1159 | ENTRY(paranoid_entry) | 1157 | ENTRY(paranoid_entry) |
1160 | UNWIND_HINT_FUNC | 1158 | UNWIND_HINT_FUNC |
1161 | cld | 1159 | cld |
1162 | SAVE_REGS 8 | 1160 | SAVE_AND_CLEAR_REGS 8 |
1163 | CLEAR_REGS_NOSPEC | ||
1164 | ENCODE_FRAME_POINTER 8 | 1161 | ENCODE_FRAME_POINTER 8 |
1165 | movl $1, %ebx | 1162 | movl $1, %ebx |
1166 | movl $MSR_GS_BASE, %ecx | 1163 | movl $MSR_GS_BASE, %ecx |
@@ -1211,8 +1208,7 @@ END(paranoid_exit) | |||
1211 | ENTRY(error_entry) | 1208 | ENTRY(error_entry) |
1212 | UNWIND_HINT_FUNC | 1209 | UNWIND_HINT_FUNC |
1213 | cld | 1210 | cld |
1214 | SAVE_REGS 8 | 1211 | SAVE_AND_CLEAR_REGS 8 |
1215 | CLEAR_REGS_NOSPEC | ||
1216 | ENCODE_FRAME_POINTER 8 | 1212 | ENCODE_FRAME_POINTER 8 |
1217 | testb $3, CS+8(%rsp) | 1213 | testb $3, CS+8(%rsp) |
1218 | jz .Lerror_kernelspace | 1214 | jz .Lerror_kernelspace |
@@ -1399,18 +1395,34 @@ ENTRY(nmi) | |||
1399 | pushq (%rdx) /* pt_regs->dx */ | 1395 | pushq (%rdx) /* pt_regs->dx */ |
1400 | pushq %rcx /* pt_regs->cx */ | 1396 | pushq %rcx /* pt_regs->cx */ |
1401 | pushq %rax /* pt_regs->ax */ | 1397 | pushq %rax /* pt_regs->ax */ |
1398 | /* | ||
1399 | * Sanitize registers of values that a speculation attack | ||
1400 | * might otherwise want to exploit. The lower registers are | ||
1401 | * likely clobbered well before they could be put to use in | ||
1402 | * a speculative execution gadget. Interleave XOR with PUSH | ||
1403 | * for better uop scheduling: | ||
1404 | */ | ||
1402 | pushq %r8 /* pt_regs->r8 */ | 1405 | pushq %r8 /* pt_regs->r8 */ |
1406 | xorq %r8, %r8 /* nospec r8 */ | ||
1403 | pushq %r9 /* pt_regs->r9 */ | 1407 | pushq %r9 /* pt_regs->r9 */ |
1408 | xorq %r9, %r9 /* nospec r9 */ | ||
1404 | pushq %r10 /* pt_regs->r10 */ | 1409 | pushq %r10 /* pt_regs->r10 */ |
1410 | xorq %r10, %r10 /* nospec r10 */ | ||
1405 | pushq %r11 /* pt_regs->r11 */ | 1411 | pushq %r11 /* pt_regs->r11 */ |
1412 | xorq %r11, %r11 /* nospec r11*/ | ||
1406 | pushq %rbx /* pt_regs->rbx */ | 1413 | pushq %rbx /* pt_regs->rbx */ |
1414 | xorl %ebx, %ebx /* nospec rbx*/ | ||
1407 | pushq %rbp /* pt_regs->rbp */ | 1415 | pushq %rbp /* pt_regs->rbp */ |
1416 | xorl %ebp, %ebp /* nospec rbp*/ | ||
1408 | pushq %r12 /* pt_regs->r12 */ | 1417 | pushq %r12 /* pt_regs->r12 */ |
1418 | xorq %r12, %r12 /* nospec r12*/ | ||
1409 | pushq %r13 /* pt_regs->r13 */ | 1419 | pushq %r13 /* pt_regs->r13 */ |
1420 | xorq %r13, %r13 /* nospec r13*/ | ||
1410 | pushq %r14 /* pt_regs->r14 */ | 1421 | pushq %r14 /* pt_regs->r14 */ |
1422 | xorq %r14, %r14 /* nospec r14*/ | ||
1411 | pushq %r15 /* pt_regs->r15 */ | 1423 | pushq %r15 /* pt_regs->r15 */ |
1424 | xorq %r15, %r15 /* nospec r15*/ | ||
1412 | UNWIND_HINT_REGS | 1425 | UNWIND_HINT_REGS |
1413 | CLEAR_REGS_NOSPEC | ||
1414 | ENCODE_FRAME_POINTER | 1426 | ENCODE_FRAME_POINTER |
1415 | 1427 | ||
1416 | /* | 1428 | /* |