[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen stable-4.18] x86/spec-ctrl: Software BHB-clearing sequences
commit 72a357f4fa4e26fd7bc7dff0fdf1174caf90624e Author: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> AuthorDate: Thu Jun 8 19:41:44 2023 +0100 Commit: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> CommitDate: Tue Apr 9 16:45:01 2024 +0100 x86/spec-ctrl: Software BHB-clearing sequences Implement clear_bhb_{tsx,loops}() as per the BHI guidance. The loops variant is set up as the "short" sequence. Introduce SCF_entry_bhb and extend SPEC_CTRL_ENTRY_* with a conditional call to selected clearing routine. Note that due to a limitation in the ALTERNATIVE capability, the TEST/JZ can't be included alongside a CALL in a single alternative block. This is going to require further work to untangle. The BHB sequences (if used) must be after the restoration of Xen's MSR_SPEC_CTRL value, which must be accounted for when judging whether it is safe to skip the safety LFENCEs. This is part of XSA-456 / CVE-2024-2201. Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Acked-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> (cherry picked from commit 954c983abceee97bf5f6230b9ae164f2c49a9aa9) --- xen/arch/x86/Makefile | 1 + xen/arch/x86/bhb-thunk.S | 98 ++++++++++++++++++++++++++++++++ xen/arch/x86/hvm/vmx/entry.S | 12 ++++ xen/arch/x86/include/asm/cpufeature.h | 3 + xen/arch/x86/include/asm/cpufeatures.h | 3 + xen/arch/x86/include/asm/spec_ctrl.h | 3 +- xen/arch/x86/include/asm/spec_ctrl_asm.h | 30 ++++++++++ xen/arch/x86/spec_ctrl.c | 39 +++++++------ 8 files changed, 171 insertions(+), 18 deletions(-) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 9f326b9e32..85b3f85608 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -15,6 +15,7 @@ alternative-y := alternative.init.o alternative-$(CONFIG_LIVEPATCH) := obj-bin-y += $(alternative-y) obj-y += apic.o +obj-y += bhb-thunk.o obj-y += bitops.o obj-bin-y += bzimage.init.o obj-bin-y += clear_page.o diff --git a/xen/arch/x86/bhb-thunk.S b/xen/arch/x86/bhb-thunk.S new file mode 100644 index 0000000000..f52cfb9bc2 --- /dev/null +++ b/xen/arch/x86/bhb-thunk.S @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Branch History Injection clearing sequences. + * + * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/branch-history-injection.html + * + * Copyright (c) 2023, 2024 XenServer. + */ + .file __FILE__ + +#include <asm/asm_defns.h> + + .section .text.entry, "ax", @progbits + +/* + * Clear the Branch History Buffer using a TSX Abort. + * + * Any TSX Abort has a side effect of clearing the BHB, even when TSX is + * disabled for e.g. TAA mitigation reasons. + */ +ENTRY(clear_bhb_tsx) + .byte 0xc7, 0xf8; .long 1f - 0f /* xbegin 1f */ +0: .byte 0xc6, 0xf8, 0 /* xabort $0 */ + int3 +1: + ret + + .size clear_bhb_tsx, . - clear_bhb_tsx + .type clear_bhb_tsx, @function + +/* + * Clear the Branch History Buffer using the software sequence. + * + * Clobbers: %eax, %ecx + * + * This executes a specific number of taken branches, sufficient to displace + * all prior entries in the history tracker, therefore removing prior + * influence on subsequent BTB lookups. + * + * Structurally, it looks like this: + * + * call 1 + * call 2 + * ... 5x jmp loop + * call 2 + * ... 5x jmp loop + * ... 5x call2's deep + * + * ret + * ret + * ret + * ret + * + * The CALL/RETs are necessary to prevent the Loop Stream Detector from + * interfering. The alignment is for performance and not safety. + * + * The "short" sequence (5 and 5) is for CPUs prior to Alder Lake / Sapphire + * Rapids (i.e. Cores prior to Golden Cove and/or Gracemont). + */ +ENTRY(clear_bhb_loops) + mov $5, %ecx + + call 1f + jmp 5f + int3 + + .align 64 +1: call 2f + ret + int3 + + .align 64 +2: mov $5, %eax + +3: jmp 4f + int3 + +4: sub $1, %eax + jnz 3b + + sub $1, %ecx + jnz 1b + + ret +5: + /* + * The Intel sequence has an LFENCE here. The purpose is to ensure + * that all prior branches have executed, before dispatching a + * subsequent indirect branch. + * + * Xen's SPEC_CTRL_ENTRY_* blocks have safety LFENCEs at the end when + * protections are active, which suffices for this purpose. + */ + + ret + + .size clear_bhb_loops, . - clear_bhb_loops + .type clear_bhb_loops, @function diff --git a/xen/arch/x86/hvm/vmx/entry.S b/xen/arch/x86/hvm/vmx/entry.S index 96b3d22080..7233e771d8 100644 --- a/xen/arch/x86/hvm/vmx/entry.S +++ b/xen/arch/x86/hvm/vmx/entry.S @@ -57,6 +57,18 @@ ENTRY(vmx_asm_vmexit_handler) wrmsr .endm ALTERNATIVE "", restore_spec_ctrl, X86_FEATURE_SC_MSR_HVM + + /* + * Clear the BHB to mitigate BHI. Used on eIBRS parts, and uses RETs + * itself so must be after we've perfomed all the RET-safety we can. + */ + testb $SCF_entry_bhb, CPUINFO_scf(%rsp) + jz .L_skip_bhb + ALTERNATIVE_2 "", \ + "call clear_bhb_loops", X86_SPEC_BHB_LOOPS, \ + "call clear_bhb_tsx", X86_SPEC_BHB_TSX +.L_skip_bhb: + ALTERNATIVE "lfence", "", X86_SPEC_NO_LFENCE_ENTRY_VMX /* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */ diff --git a/xen/arch/x86/include/asm/cpufeature.h b/xen/arch/x86/include/asm/cpufeature.h index 3c57f55de0..7a312c485e 100644 --- a/xen/arch/x86/include/asm/cpufeature.h +++ b/xen/arch/x86/include/asm/cpufeature.h @@ -228,6 +228,9 @@ static inline bool boot_cpu_has(unsigned int feat) #define cpu_bug_fpu_ptrs boot_cpu_has(X86_BUG_FPU_PTRS) #define cpu_bug_null_seg boot_cpu_has(X86_BUG_NULL_SEG) +#define cpu_has_bhb_seq (boot_cpu_has(X86_SPEC_BHB_TSX) || \ + boot_cpu_has(X86_SPEC_BHB_LOOPS)) + enum _cache_type { CACHE_TYPE_NULL = 0, CACHE_TYPE_DATA = 1, diff --git a/xen/arch/x86/include/asm/cpufeatures.h b/xen/arch/x86/include/asm/cpufeatures.h index 6422c66b0f..bada8912e0 100644 --- a/xen/arch/x86/include/asm/cpufeatures.h +++ b/xen/arch/x86/include/asm/cpufeatures.h @@ -56,5 +56,8 @@ XEN_CPUFEATURE(IBPB_ENTRY_HVM, X86_SYNTH(29)) /* MSR_PRED_CMD used by Xen for #define X86_SPEC_NO_LFENCE_ENTRY_INTR X86_BUG(17) /* (No) safety LFENCE for SPEC_CTRL_ENTRY_INTR. */ #define X86_SPEC_NO_LFENCE_ENTRY_VMX X86_BUG(18) /* (No) safety LFENCE for SPEC_CTRL_ENTRY_VMX. */ +#define X86_SPEC_BHB_TSX X86_BUG(19) /* Use clear_bhb_tsx for BHI mitigation. */ +#define X86_SPEC_BHB_LOOPS X86_BUG(20) /* Use clear_bhb_loops for BHI mitigation.*/ + /* Total number of capability words, inc synth and bug words. */ #define NCAPINTS (FSCAPINTS + X86_NR_SYNTH + X86_NR_BUG) /* N 32-bit words worth of info */ diff --git a/xen/arch/x86/include/asm/spec_ctrl.h b/xen/arch/x86/include/asm/spec_ctrl.h index b2d2c25842..72347ef2b9 100644 --- a/xen/arch/x86/include/asm/spec_ctrl.h +++ b/xen/arch/x86/include/asm/spec_ctrl.h @@ -24,6 +24,7 @@ #define SCF_verw (1 << 3) #define SCF_ist_ibpb (1 << 4) #define SCF_entry_ibpb (1 << 5) +#define SCF_entry_bhb (1 << 6) /* * The IST paths (NMI/#MC) can interrupt any arbitrary context. Some @@ -42,7 +43,7 @@ * Some speculative protections are per-domain. These settings are merged * into the top-of-stack block in the context switch path. */ -#define SCF_DOM_MASK (SCF_verw | SCF_entry_ibpb) +#define SCF_DOM_MASK (SCF_verw | SCF_entry_ibpb | SCF_entry_bhb) #ifndef __ASSEMBLY__ diff --git a/xen/arch/x86/include/asm/spec_ctrl_asm.h b/xen/arch/x86/include/asm/spec_ctrl_asm.h index f697d17616..989ff67db5 100644 --- a/xen/arch/x86/include/asm/spec_ctrl_asm.h +++ b/xen/arch/x86/include/asm/spec_ctrl_asm.h @@ -273,6 +273,17 @@ ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=0), \ X86_FEATURE_SC_MSR_PV + /* + * Clear the BHB to mitigate BHI. Used on eIBRS parts, and uses RETs + * itself so must be after we've perfomed all the RET-safety we can. + */ + testb $SCF_entry_bhb, %bl + jz .L\@_skip_bhb + ALTERNATIVE_2 "", \ + "call clear_bhb_loops", X86_SPEC_BHB_LOOPS, \ + "call clear_bhb_tsx", X86_SPEC_BHB_TSX +.L\@_skip_bhb: + ALTERNATIVE "lfence", "", X86_SPEC_NO_LFENCE_ENTRY_PV .endm @@ -311,6 +322,13 @@ ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=1), \ X86_FEATURE_SC_MSR_PV + testb $SCF_entry_bhb, %bl + jz .L\@_skip_bhb + ALTERNATIVE_2 "", \ + "call clear_bhb_loops", X86_SPEC_BHB_LOOPS, \ + "call clear_bhb_tsx", X86_SPEC_BHB_TSX +.L\@_skip_bhb: + ALTERNATIVE "lfence", "", X86_SPEC_NO_LFENCE_ENTRY_INTR .endm @@ -411,6 +429,18 @@ .L\@_skip_msr_spec_ctrl: + /* + * Clear the BHB to mitigate BHI. Used on eIBRS parts, and uses RETs + * itself so must be after we've perfomed all the RET-safety we can. + */ + testb $SCF_entry_bhb, %bl + jz .L\@_skip_bhb + + ALTERNATIVE_2 "", \ + "call clear_bhb_loops", X86_SPEC_BHB_LOOPS, \ + "call clear_bhb_tsx", X86_SPEC_BHB_TSX +.L\@_skip_bhb: + lfence .endm diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c index 6a1eb14cdf..131127d856 100644 --- a/xen/arch/x86/spec_ctrl.c +++ b/xen/arch/x86/spec_ctrl.c @@ -2182,38 +2182,43 @@ void __init init_speculation_mitigations(void) /* * SPEC_CTRL_ENTRY_FROM_PV conditional safety * - * DO_SPEC_CTRL_ENTRY (X86_FEATURE_SC_MSR_PV if used) is an - * unconditional WRMSR as the last action. + * A BHB sequence, if used, is a conditional action and last. If we + * have this, then we must have the LFENCE. * - * If we have it, or we're not using any prior conditional mitigation, - * then it's safe to drop the LFENCE. + * Otherwise, DO_SPEC_CTRL_ENTRY (X86_FEATURE_SC_MSR_PV if used) is an + * unconditional WRMSR. If we do have it, or we're not using any + * prior conditional block, then it's safe to drop the LFENCE. */ - if ( boot_cpu_has(X86_FEATURE_SC_MSR_PV) || - !boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) ) + if ( !cpu_has_bhb_seq && + (boot_cpu_has(X86_FEATURE_SC_MSR_PV) || + !boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV)) ) setup_force_cpu_cap(X86_SPEC_NO_LFENCE_ENTRY_PV); /* * SPEC_CTRL_ENTRY_FROM_INTR conditional safety * - * DO_SPEC_CTRL_ENTRY (X86_FEATURE_SC_MSR_PV if used) is an - * unconditional WRMSR as the last action. + * A BHB sequence, if used, is a conditional action and last. If we + * have this, then we must have the LFENCE. * - * If we have it, or we have no protections active in the block that - * is skipped when interrupting guest context, then it's safe to drop - * the LFENCE. + * Otherwise DO_SPEC_CTRL_ENTRY (X86_FEATURE_SC_MSR_PV if used) is an + * unconditional WRMSR. If we have it, or we have no protections + * active in the block that is skipped when interrupting guest + * context, then it's safe to drop the LFENCE. */ - if ( boot_cpu_has(X86_FEATURE_SC_MSR_PV) || - (!boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) && - !boot_cpu_has(X86_FEATURE_SC_RSB_PV)) ) + if ( !cpu_has_bhb_seq && + (boot_cpu_has(X86_FEATURE_SC_MSR_PV) || + (!boot_cpu_has(X86_FEATURE_IBPB_ENTRY_PV) && + !boot_cpu_has(X86_FEATURE_SC_RSB_PV))) ) setup_force_cpu_cap(X86_SPEC_NO_LFENCE_ENTRY_INTR); /* * SPEC_CTRL_ENTRY_FROM_VMX conditional safety * - * Currently there are no safety actions with conditional branches, so - * no need for the extra safety LFENCE. + * A BHB sequence, if used, is the only conditional action, so if we + * don't have it, we don't need the safety LFENCE. */ - setup_force_cpu_cap(X86_SPEC_NO_LFENCE_ENTRY_VMX); + if ( !cpu_has_bhb_seq ) + setup_force_cpu_cap(X86_SPEC_NO_LFENCE_ENTRY_VMX); } /* -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.18
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |