Skip to content

Commit 7390db8

Browse files
pa1guptaKAGA-KOKO
authored andcommitted
x86/bhi: Add support for clearing branch history at syscall entry
Branch History Injection (BHI) attacks may allow a malicious application to influence indirect branch prediction in kernel by poisoning the branch history. eIBRS isolates indirect branch targets in ring0. The BHB can still influence the choice of indirect branch predictor entry, and although branch predictor entries are isolated between modes when eIBRS is enabled, the BHB itself is not isolated between modes. Alder Lake and new processors supports a hardware control BHI_DIS_S to mitigate BHI. For older processors Intel has released a software sequence to clear the branch history on parts that don't support BHI_DIS_S. Add support to execute the software sequence at syscall entry and VMexit to overwrite the branch history. For now, branch history is not cleared at interrupt entry, as malicious applications are not believed to have sufficient control over the registers, since previous register state is cleared at interrupt entry. Researchers continue to poke at this area and it may become necessary to clear at interrupt entry as well in the future. This mitigation is only defined here. It is enabled later. Signed-off-by: Pawan Gupta <[email protected]> Co-developed-by: Daniel Sneddon <[email protected]> Signed-off-by: Daniel Sneddon <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Alexandre Chartre <[email protected]> Reviewed-by: Josh Poimboeuf <[email protected]>
1 parent 1e3ad78 commit 7390db8

File tree

7 files changed

+96
-3
lines changed

7 files changed

+96
-3
lines changed

arch/x86/entry/common.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ static __always_inline bool int80_is_external(void)
189189
}
190190

191191
/**
192-
* int80_emulation - 32-bit legacy syscall entry
192+
* do_int80_emulation - 32-bit legacy syscall C entry from asm
193193
*
194194
* This entry point can be used by 32-bit and 64-bit programs to perform
195195
* 32-bit system calls. Instances of INT $0x80 can be found inline in
@@ -207,7 +207,7 @@ static __always_inline bool int80_is_external(void)
207207
* eax: system call number
208208
* ebx, ecx, edx, esi, edi, ebp: arg1 - arg 6
209209
*/
210-
DEFINE_IDTENTRY_RAW(int80_emulation)
210+
__visible noinstr void do_int80_emulation(struct pt_regs *regs)
211211
{
212212
int nr;
213213

arch/x86/entry/entry_64.S

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
116116
/* clobbers %rax, make sure it is after saving the syscall nr */
117117
IBRS_ENTER
118118
UNTRAIN_RET
119+
CLEAR_BRANCH_HISTORY
119120

120121
call do_syscall_64 /* returns with IRQs disabled */
121122

@@ -1491,3 +1492,63 @@ SYM_CODE_START_NOALIGN(rewind_stack_and_make_dead)
14911492
call make_task_dead
14921493
SYM_CODE_END(rewind_stack_and_make_dead)
14931494
.popsection
1495+
1496+
/*
1497+
* This sequence executes branches in order to remove user branch information
1498+
* from the branch history tracker in the Branch Predictor, therefore removing
1499+
* user influence on subsequent BTB lookups.
1500+
*
1501+
* It should be used on parts prior to Alder Lake. Newer parts should use the
1502+
* BHI_DIS_S hardware control instead. If a pre-Alder Lake part is being
1503+
* virtualized on newer hardware the VMM should protect against BHI attacks by
1504+
* setting BHI_DIS_S for the guests.
1505+
*
1506+
* CALLs/RETs are necessary to prevent Loop Stream Detector(LSD) from engaging
1507+
* and not clearing the branch history. The call tree looks like:
1508+
*
1509+
* call 1
1510+
* call 2
1511+
* call 2
1512+
* call 2
1513+
* call 2
1514+
* call 2
1515+
* ret
1516+
* ret
1517+
* ret
1518+
* ret
1519+
* ret
1520+
* ret
1521+
*
1522+
* This means that the stack is non-constant and ORC can't unwind it with %rsp
1523+
* alone. Therefore we unconditionally set up the frame pointer, which allows
1524+
* ORC to unwind properly.
1525+
*
1526+
* The alignment is for performance and not for safety, and may be safely
1527+
* refactored in the future if needed.
1528+
*/
1529+
SYM_FUNC_START(clear_bhb_loop)
1530+
push %rbp
1531+
mov %rsp, %rbp
1532+
movl $5, %ecx
1533+
ANNOTATE_INTRA_FUNCTION_CALL
1534+
call 1f
1535+
jmp 5f
1536+
.align 64, 0xcc
1537+
ANNOTATE_INTRA_FUNCTION_CALL
1538+
1: call 2f
1539+
RET
1540+
.align 64, 0xcc
1541+
2: movl $5, %eax
1542+
3: jmp 4f
1543+
nop
1544+
4: sub $1, %eax
1545+
jnz 3b
1546+
sub $1, %ecx
1547+
jnz 1b
1548+
RET
1549+
5: lfence
1550+
pop %rbp
1551+
RET
1552+
SYM_FUNC_END(clear_bhb_loop)
1553+
EXPORT_SYMBOL_GPL(clear_bhb_loop)
1554+
STACK_FRAME_NON_STANDARD(clear_bhb_loop)

arch/x86/entry/entry_64_compat.S

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL)
9292

9393
IBRS_ENTER
9494
UNTRAIN_RET
95+
CLEAR_BRANCH_HISTORY
9596

9697
/*
9798
* SYSENTER doesn't filter flags, so we need to clear NT and AC
@@ -206,6 +207,7 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_after_hwframe, SYM_L_GLOBAL)
206207

207208
IBRS_ENTER
208209
UNTRAIN_RET
210+
CLEAR_BRANCH_HISTORY
209211

210212
movq %rsp, %rdi
211213
call do_fast_syscall_32
@@ -276,3 +278,17 @@ SYM_INNER_LABEL(entry_SYSRETL_compat_end, SYM_L_GLOBAL)
276278
ANNOTATE_NOENDBR
277279
int3
278280
SYM_CODE_END(entry_SYSCALL_compat)
281+
282+
/*
283+
* int 0x80 is used by 32 bit mode as a system call entry. Normally idt entries
284+
* point to C routines, however since this is a system call interface the branch
285+
* history needs to be scrubbed to protect against BHI attacks, and that
286+
* scrubbing needs to take place in assembly code prior to entering any C
287+
* routines.
288+
*/
289+
SYM_CODE_START(int80_emulation)
290+
ANNOTATE_NOENDBR
291+
UNWIND_HINT_FUNC
292+
CLEAR_BRANCH_HISTORY
293+
jmp do_int80_emulation
294+
SYM_CODE_END(int80_emulation)

arch/x86/include/asm/cpufeatures.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,11 +461,12 @@
461461

462462
/*
463463
* Extended auxiliary flags: Linux defined - for features scattered in various
464-
* CPUID levels like 0x80000022, etc.
464+
* CPUID levels like 0x80000022, etc and Linux defined features.
465465
*
466466
* Reuse free bits when adding new feature flags!
467467
*/
468468
#define X86_FEATURE_AMD_LBR_PMC_FREEZE (21*32+ 0) /* AMD LBR and PMC Freeze */
469+
#define X86_FEATURE_CLEAR_BHB_LOOP (21*32+ 1) /* "" Clear branch history at syscall entry using SW loop */
469470

470471
/*
471472
* BUG word(s)

arch/x86/include/asm/nospec-branch.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,14 @@
326326
ALTERNATIVE "", __stringify(verw _ASM_RIP(mds_verw_sel)), X86_FEATURE_CLEAR_CPU_BUF
327327
.endm
328328

329+
#ifdef CONFIG_X86_64
330+
.macro CLEAR_BRANCH_HISTORY
331+
ALTERNATIVE "", "call clear_bhb_loop", X86_FEATURE_CLEAR_BHB_LOOP
332+
.endm
333+
#else
334+
#define CLEAR_BRANCH_HISTORY
335+
#endif
336+
329337
#else /* __ASSEMBLY__ */
330338

331339
#define ANNOTATE_RETPOLINE_SAFE \
@@ -368,6 +376,10 @@ extern void srso_alias_return_thunk(void);
368376
extern void entry_untrain_ret(void);
369377
extern void entry_ibpb(void);
370378

379+
#ifdef CONFIG_X86_64
380+
extern void clear_bhb_loop(void);
381+
#endif
382+
371383
extern void (*x86_return_thunk)(void);
372384

373385
extern void __warn_thunk(void);

arch/x86/include/asm/syscall.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ static inline int syscall_get_arch(struct task_struct *task)
125125
}
126126

127127
bool do_syscall_64(struct pt_regs *regs, int nr);
128+
void do_int80_emulation(struct pt_regs *regs);
128129

129130
#endif /* CONFIG_X86_32 */
130131

arch/x86/kvm/vmx/vmenter.S

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ SYM_INNER_LABEL_ALIGN(vmx_vmexit, SYM_L_GLOBAL)
275275

276276
call vmx_spec_ctrl_restore_host
277277

278+
CLEAR_BRANCH_HISTORY
279+
278280
/* Put return value in AX */
279281
mov %_ASM_BX, %_ASM_AX
280282

0 commit comments

Comments
 (0)