Skip to content

Commit 9f725ee

Browse files
Daniel Sneddonhansendc
authored andcommitted
x86/bpf: Add IBHF call at end of classic BPF
Classic BPF programs can be run by unprivileged users, allowing unprivileged code to execute inside the kernel. Attackers can use this to craft branch history in kernel mode that can influence the target of indirect branches. BHI_DIS_S provides user-kernel isolation of branch history, but cBPF can be used to bypass this protection by crafting branch history in kernel mode. To stop intra-mode attacks via cBPF programs, Intel created a new instruction Indirect Branch History Fence (IBHF). IBHF prevents the predicted targets of subsequent indirect branches from being influenced by branch history prior to the IBHF. IBHF is only effective while BHI_DIS_S is enabled. Add the IBHF instruction to cBPF jitted code's exit path. Add the new fence when the hardware mitigation is enabled (i.e., X86_FEATURE_CLEAR_BHB_HW is set) or after the software sequence (X86_FEATURE_CLEAR_BHB_LOOP) is being used in a virtual machine. Note that X86_FEATURE_CLEAR_BHB_HW and X86_FEATURE_CLEAR_BHB_LOOP are mutually exclusive, so the JIT compiler will only emit the new fence, not the SW sequence, when X86_FEATURE_CLEAR_BHB_HW is set. Hardware that enumerates BHI_NO basically has BHI_DIS_S protections always enabled, regardless of the value of BHI_DIS_S. Since BHI_DIS_S doesn't protect against intra-mode attacks, enumerate BHI bug on BHI_NO hardware as well. Signed-off-by: Daniel Sneddon <[email protected]> Signed-off-by: Pawan Gupta <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Acked-by: Daniel Borkmann <[email protected]> Reviewed-by: Alexandre Chartre <[email protected]>
1 parent d4e89d2 commit 9f725ee

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

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: 19 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)
@@ -1522,6 +1524,23 @@ static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
15221524
EMIT1(0x59); /* pop rcx */
15231525
EMIT1(0x58); /* pop rax */
15241526
}
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+
IS_ENABLED(CONFIG_X86_64))) {
1532+
/*
1533+
* Add an Indirect Branch History Fence (IBHF). IBHF acts as a
1534+
* fence preventing branch history from before the fence from
1535+
* affecting indirect branches after the fence. This is
1536+
* specifically used in cBPF jitted code to prevent Intra-mode
1537+
* BHI attacks. The IBHF instruction is designed to be a NOP on
1538+
* hardware that doesn't need or support it. The REP and REX.W
1539+
* prefixes are required by the microcode, and they also ensure
1540+
* that the NOP is unlikely to be used in existing code.
1541+
*/
1542+
EMIT5(0xF3, 0x48, 0x0F, 0x1E, 0xF8); /* ibhf */
1543+
}
15251544
*pprog = prog;
15261545
return 0;
15271546
}

0 commit comments

Comments
 (0)