Skip to content

Commit caf12fa

Browse files
committed
Merge tag 'ibti-hisory-for-linus-2025-05-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 IBTI mitigation from Dave Hansen: "Mitigate Intra-mode Branch History Injection via classic BFP programs This adds the branch history clearing mitigation to cBPF programs for x86. Intra-mode BHI attacks via cBPF a.k.a IBTI-History was reported by researchers at VUSec. For hardware that doesn't support BHI_DIS_S, the recommended mitigation is to run the short software sequence followed by the IBHF instruction after cBPF execution. On hardware that does support BHI_DIS_S, enable BHI_DIS_S and execute the IBHF after cBPF execution. The Indirect Branch History Fence (IBHF) is a new instruction that prevents indirect branch target predictions after the barrier from using branch history from before the barrier while BHI_DIS_S is enabled. On older systems this will map to a NOP. It is recommended to add this fence at the end of the cBPF program to support VM migration. This instruction is required on newer parts with BHI_NO to fully mitigate against these attacks. The current code disables the mitigation for anything running with the SYS_ADMIN capability bit set. The intention was not to waste time mitigating a process that has access to anything it wants anyway" * tag 'ibti-hisory-for-linus-2025-05-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/bhi: Do not set BHI_DIS_S in 32-bit mode x86/bpf: Add IBHF call at end of classic BPF x86/bpf: Call branch history clearing sequence on exit
2 parents 82f2b0b + 073fdbe commit caf12fa

File tree

3 files changed

+60
-6
lines changed

3 files changed

+60
-6
lines changed

arch/x86/kernel/cpu/bugs.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,11 +1697,11 @@ static void __init bhi_select_mitigation(void)
16971697
return;
16981698
}
16991699

1700-
/* Mitigate in hardware if supported */
1701-
if (spec_ctrl_bhi_dis())
1700+
if (!IS_ENABLED(CONFIG_X86_64))
17021701
return;
17031702

1704-
if (!IS_ENABLED(CONFIG_X86_64))
1703+
/* Mitigate in hardware if supported */
1704+
if (spec_ctrl_bhi_dis())
17051705
return;
17061706

17071707
if (bhi_mitigation == BHI_MITIGATION_VMEXIT_ONLY) {

arch/x86/kernel/cpu/common.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,9 +1439,12 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
14391439
if (vulnerable_to_rfds(x86_arch_cap_msr))
14401440
setup_force_cpu_bug(X86_BUG_RFDS);
14411441

1442-
/* When virtualized, eIBRS could be hidden, assume vulnerable */
1443-
if (!(x86_arch_cap_msr & ARCH_CAP_BHI_NO) &&
1444-
!cpu_matches(cpu_vuln_whitelist, NO_BHI) &&
1442+
/*
1443+
* Intel parts with eIBRS are vulnerable to BHI attacks. Parts with
1444+
* BHI_NO still need to use the BHI mitigation to prevent Intra-mode
1445+
* attacks. When virtualized, eIBRS could be hidden, assume vulnerable.
1446+
*/
1447+
if (!cpu_matches(cpu_vuln_whitelist, NO_BHI) &&
14451448
(boot_cpu_has(X86_FEATURE_IBRS_ENHANCED) ||
14461449
boot_cpu_has(X86_FEATURE_HYPERVISOR)))
14471450
setup_force_cpu_bug(X86_BUG_BHI);

arch/x86/net/bpf_jit_comp.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
4141
#define EMIT2(b1, b2) EMIT((b1) + ((b2) << 8), 2)
4242
#define EMIT3(b1, b2, b3) EMIT((b1) + ((b2) << 8) + ((b3) << 16), 3)
4343
#define EMIT4(b1, b2, b3, b4) EMIT((b1) + ((b2) << 8) + ((b3) << 16) + ((b4) << 24), 4)
44+
#define EMIT5(b1, b2, b3, b4, b5) \
45+
do { EMIT1(b1); EMIT4(b2, b3, b4, b5); } while (0)
4446

4547
#define EMIT1_off32(b1, off) \
4648
do { EMIT1(b1); EMIT(off, 4); } while (0)
@@ -1502,6 +1504,48 @@ static void emit_priv_frame_ptr(u8 **pprog, void __percpu *priv_frame_ptr)
15021504
#define PRIV_STACK_GUARD_SZ 8
15031505
#define PRIV_STACK_GUARD_VAL 0xEB9F12345678eb9fULL
15041506

1507+
static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
1508+
struct bpf_prog *bpf_prog)
1509+
{
1510+
u8 *prog = *pprog;
1511+
u8 *func;
1512+
1513+
if (cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_LOOP)) {
1514+
/* The clearing sequence clobbers eax and ecx. */
1515+
EMIT1(0x50); /* push rax */
1516+
EMIT1(0x51); /* push rcx */
1517+
ip += 2;
1518+
1519+
func = (u8 *)clear_bhb_loop;
1520+
ip += x86_call_depth_emit_accounting(&prog, func, ip);
1521+
1522+
if (emit_call(&prog, func, ip))
1523+
return -EINVAL;
1524+
EMIT1(0x59); /* pop rcx */
1525+
EMIT1(0x58); /* pop rax */
1526+
}
1527+
/* Insert IBHF instruction */
1528+
if ((cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_LOOP) &&
1529+
cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) ||
1530+
cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_HW)) {
1531+
/*
1532+
* Add an Indirect Branch History Fence (IBHF). IBHF acts as a
1533+
* fence preventing branch history from before the fence from
1534+
* affecting indirect branches after the fence. This is
1535+
* specifically used in cBPF jitted code to prevent Intra-mode
1536+
* BHI attacks. The IBHF instruction is designed to be a NOP on
1537+
* hardware that doesn't need or support it. The REP and REX.W
1538+
* prefixes are required by the microcode, and they also ensure
1539+
* that the NOP is unlikely to be used in existing code.
1540+
*
1541+
* IBHF is not a valid instruction in 32-bit mode.
1542+
*/
1543+
EMIT5(0xF3, 0x48, 0x0F, 0x1E, 0xF8); /* ibhf */
1544+
}
1545+
*pprog = prog;
1546+
return 0;
1547+
}
1548+
15051549
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
15061550
int oldproglen, struct jit_context *ctx, bool jmp_padding)
15071551
{
@@ -2544,6 +2588,13 @@ st: if (is_imm8(insn->off))
25442588
seen_exit = true;
25452589
/* Update cleanup_addr */
25462590
ctx->cleanup_addr = proglen;
2591+
if (bpf_prog_was_classic(bpf_prog) &&
2592+
!capable(CAP_SYS_ADMIN)) {
2593+
u8 *ip = image + addrs[i - 1];
2594+
2595+
if (emit_spectre_bhb_barrier(&prog, ip, bpf_prog))
2596+
return -EINVAL;
2597+
}
25472598
if (bpf_prog->aux->exception_boundary) {
25482599
pop_callee_regs(&prog, all_callee_regs_used);
25492600
pop_r12(&prog);

0 commit comments

Comments
 (0)