diff options
-rw-r--r-- | arch/x86/entry/calling.h | 17 | ||||
-rw-r--r-- | arch/x86/entry/entry_64.S | 21 | ||||
-rw-r--r-- | arch/x86/include/asm/cpufeatures.h | 2 |
3 files changed, 37 insertions, 3 deletions
diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h index 9f1f9e3b8230..7ce7ac9d9d3f 100644 --- a/arch/x86/entry/calling.h +++ b/arch/x86/entry/calling.h | |||
@@ -314,6 +314,23 @@ For 32-bit we have the following conventions - kernel is built with | |||
314 | 314 | ||
315 | #endif | 315 | #endif |
316 | 316 | ||
317 | /* | ||
318 | * Mitigate Spectre v1 for conditional swapgs code paths. | ||
319 | * | ||
320 | * FENCE_SWAPGS_USER_ENTRY is used in the user entry swapgs code path, to | ||
321 | * prevent a speculative swapgs when coming from kernel space. | ||
322 | * | ||
323 | * FENCE_SWAPGS_KERNEL_ENTRY is used in the kernel entry non-swapgs code path, | ||
324 | * to prevent the swapgs from getting speculatively skipped when coming from | ||
325 | * user space. | ||
326 | */ | ||
327 | .macro FENCE_SWAPGS_USER_ENTRY | ||
328 | ALTERNATIVE "", "lfence", X86_FEATURE_FENCE_SWAPGS_USER | ||
329 | .endm | ||
330 | .macro FENCE_SWAPGS_KERNEL_ENTRY | ||
331 | ALTERNATIVE "", "lfence", X86_FEATURE_FENCE_SWAPGS_KERNEL | ||
332 | .endm | ||
333 | |||
317 | .macro STACKLEAK_ERASE_NOCLOBBER | 334 | .macro STACKLEAK_ERASE_NOCLOBBER |
318 | #ifdef CONFIG_GCC_PLUGIN_STACKLEAK | 335 | #ifdef CONFIG_GCC_PLUGIN_STACKLEAK |
319 | PUSH_AND_CLEAR_REGS | 336 | PUSH_AND_CLEAR_REGS |
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index a829dd3117d0..57a0d96d6beb 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S | |||
@@ -519,7 +519,7 @@ ENTRY(interrupt_entry) | |||
519 | testb $3, CS-ORIG_RAX+8(%rsp) | 519 | testb $3, CS-ORIG_RAX+8(%rsp) |
520 | jz 1f | 520 | jz 1f |
521 | SWAPGS | 521 | SWAPGS |
522 | 522 | FENCE_SWAPGS_USER_ENTRY | |
523 | /* | 523 | /* |
524 | * Switch to the thread stack. The IRET frame and orig_ax are | 524 | * Switch to the thread stack. The IRET frame and orig_ax are |
525 | * on the stack, as well as the return address. RDI..R12 are | 525 | * on the stack, as well as the return address. RDI..R12 are |
@@ -549,8 +549,10 @@ ENTRY(interrupt_entry) | |||
549 | UNWIND_HINT_FUNC | 549 | UNWIND_HINT_FUNC |
550 | 550 | ||
551 | movq (%rdi), %rdi | 551 | movq (%rdi), %rdi |
552 | jmpq 2f | ||
552 | 1: | 553 | 1: |
553 | 554 | FENCE_SWAPGS_KERNEL_ENTRY | |
555 | 2: | ||
554 | PUSH_AND_CLEAR_REGS save_ret=1 | 556 | PUSH_AND_CLEAR_REGS save_ret=1 |
555 | ENCODE_FRAME_POINTER 8 | 557 | ENCODE_FRAME_POINTER 8 |
556 | 558 | ||
@@ -1221,6 +1223,13 @@ ENTRY(paranoid_entry) | |||
1221 | */ | 1223 | */ |
1222 | SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14 | 1224 | SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14 |
1223 | 1225 | ||
1226 | /* | ||
1227 | * The above SAVE_AND_SWITCH_TO_KERNEL_CR3 macro doesn't do an | ||
1228 | * unconditional CR3 write, even in the PTI case. So do an lfence | ||
1229 | * to prevent GS speculation, regardless of whether PTI is enabled. | ||
1230 | */ | ||
1231 | FENCE_SWAPGS_KERNEL_ENTRY | ||
1232 | |||
1224 | ret | 1233 | ret |
1225 | END(paranoid_entry) | 1234 | END(paranoid_entry) |
1226 | 1235 | ||
@@ -1271,6 +1280,7 @@ ENTRY(error_entry) | |||
1271 | * from user mode due to an IRET fault. | 1280 | * from user mode due to an IRET fault. |
1272 | */ | 1281 | */ |
1273 | SWAPGS | 1282 | SWAPGS |
1283 | FENCE_SWAPGS_USER_ENTRY | ||
1274 | /* We have user CR3. Change to kernel CR3. */ | 1284 | /* We have user CR3. Change to kernel CR3. */ |
1275 | SWITCH_TO_KERNEL_CR3 scratch_reg=%rax | 1285 | SWITCH_TO_KERNEL_CR3 scratch_reg=%rax |
1276 | 1286 | ||
@@ -1292,6 +1302,8 @@ ENTRY(error_entry) | |||
1292 | CALL_enter_from_user_mode | 1302 | CALL_enter_from_user_mode |
1293 | ret | 1303 | ret |
1294 | 1304 | ||
1305 | .Lerror_entry_done_lfence: | ||
1306 | FENCE_SWAPGS_KERNEL_ENTRY | ||
1295 | .Lerror_entry_done: | 1307 | .Lerror_entry_done: |
1296 | TRACE_IRQS_OFF | 1308 | TRACE_IRQS_OFF |
1297 | ret | 1309 | ret |
@@ -1310,7 +1322,7 @@ ENTRY(error_entry) | |||
1310 | cmpq %rax, RIP+8(%rsp) | 1322 | cmpq %rax, RIP+8(%rsp) |
1311 | je .Lbstep_iret | 1323 | je .Lbstep_iret |
1312 | cmpq $.Lgs_change, RIP+8(%rsp) | 1324 | cmpq $.Lgs_change, RIP+8(%rsp) |
1313 | jne .Lerror_entry_done | 1325 | jne .Lerror_entry_done_lfence |
1314 | 1326 | ||
1315 | /* | 1327 | /* |
1316 | * hack: .Lgs_change can fail with user gsbase. If this happens, fix up | 1328 | * hack: .Lgs_change can fail with user gsbase. If this happens, fix up |
@@ -1318,6 +1330,7 @@ ENTRY(error_entry) | |||
1318 | * .Lgs_change's error handler with kernel gsbase. | 1330 | * .Lgs_change's error handler with kernel gsbase. |
1319 | */ | 1331 | */ |
1320 | SWAPGS | 1332 | SWAPGS |
1333 | FENCE_SWAPGS_USER_ENTRY | ||
1321 | SWITCH_TO_KERNEL_CR3 scratch_reg=%rax | 1334 | SWITCH_TO_KERNEL_CR3 scratch_reg=%rax |
1322 | jmp .Lerror_entry_done | 1335 | jmp .Lerror_entry_done |
1323 | 1336 | ||
@@ -1332,6 +1345,7 @@ ENTRY(error_entry) | |||
1332 | * gsbase and CR3. Switch to kernel gsbase and CR3: | 1345 | * gsbase and CR3. Switch to kernel gsbase and CR3: |
1333 | */ | 1346 | */ |
1334 | SWAPGS | 1347 | SWAPGS |
1348 | FENCE_SWAPGS_USER_ENTRY | ||
1335 | SWITCH_TO_KERNEL_CR3 scratch_reg=%rax | 1349 | SWITCH_TO_KERNEL_CR3 scratch_reg=%rax |
1336 | 1350 | ||
1337 | /* | 1351 | /* |
@@ -1423,6 +1437,7 @@ ENTRY(nmi) | |||
1423 | 1437 | ||
1424 | swapgs | 1438 | swapgs |
1425 | cld | 1439 | cld |
1440 | FENCE_SWAPGS_USER_ENTRY | ||
1426 | SWITCH_TO_KERNEL_CR3 scratch_reg=%rdx | 1441 | SWITCH_TO_KERNEL_CR3 scratch_reg=%rdx |
1427 | movq %rsp, %rdx | 1442 | movq %rsp, %rdx |
1428 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp | 1443 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp |
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 998c2cc08363..4393278666d9 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h | |||
@@ -281,6 +281,8 @@ | |||
281 | #define X86_FEATURE_CQM_OCCUP_LLC (11*32+ 1) /* LLC occupancy monitoring */ | 281 | #define X86_FEATURE_CQM_OCCUP_LLC (11*32+ 1) /* LLC occupancy monitoring */ |
282 | #define X86_FEATURE_CQM_MBM_TOTAL (11*32+ 2) /* LLC Total MBM monitoring */ | 282 | #define X86_FEATURE_CQM_MBM_TOTAL (11*32+ 2) /* LLC Total MBM monitoring */ |
283 | #define X86_FEATURE_CQM_MBM_LOCAL (11*32+ 3) /* LLC Local MBM monitoring */ | 283 | #define X86_FEATURE_CQM_MBM_LOCAL (11*32+ 3) /* LLC Local MBM monitoring */ |
284 | #define X86_FEATURE_FENCE_SWAPGS_USER (11*32+ 4) /* "" LFENCE in user entry SWAPGS path */ | ||
285 | #define X86_FEATURE_FENCE_SWAPGS_KERNEL (11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */ | ||
284 | 286 | ||
285 | /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ | 287 | /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ |
286 | #define X86_FEATURE_AVX512_BF16 (12*32+ 5) /* AVX512 BFLOAT16 instructions */ | 288 | #define X86_FEATURE_AVX512_BF16 (12*32+ 5) /* AVX512 BFLOAT16 instructions */ |