x86/bpf: Add IBHF call at end of classic BPF
authorDaniel Sneddon <daniel.sneddon@linux.intel.com>
Mon, 5 May 2025 21:35:12 +0000 (14:35 -0700)
committerDave Hansen <dave.hansen@linux.intel.com>
Tue, 6 May 2025 15:18:48 +0000 (08:18 -0700)
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 <daniel.sneddon@linux.intel.com>
Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Alexandre Chartre <alexandre.chartre@oracle.com>
arch/x86/kernel/cpu/common.c
arch/x86/net/bpf_jit_comp.c

index 12126adbc3a9a7e2b767e024ececd3940098f3e8..5ab13d9241c0ad203a1df4f058aca99b99047627 100644 (file)
@@ -1439,9 +1439,12 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
        if (vulnerable_to_rfds(x86_arch_cap_msr))
                setup_force_cpu_bug(X86_BUG_RFDS);
 
-       /* When virtualized, eIBRS could be hidden, assume vulnerable */
-       if (!(x86_arch_cap_msr & ARCH_CAP_BHI_NO) &&
-           !cpu_matches(cpu_vuln_whitelist, NO_BHI) &&
+       /*
+        * Intel parts with eIBRS are vulnerable to BHI attacks. Parts with
+        * BHI_NO still need to use the BHI mitigation to prevent Intra-mode
+        * attacks.  When virtualized, eIBRS could be hidden, assume vulnerable.
+        */
+       if (!cpu_matches(cpu_vuln_whitelist, NO_BHI) &&
            (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED) ||
             boot_cpu_has(X86_FEATURE_HYPERVISOR)))
                setup_force_cpu_bug(X86_BUG_BHI);
index 6fb786c8b2aa380952c6937c724a98af1b43e8b0..e472572392ef6c904ed233ec99ecd6ab29797c51 100644 (file)
@@ -41,6 +41,8 @@ static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
 #define EMIT2(b1, b2)          EMIT((b1) + ((b2) << 8), 2)
 #define EMIT3(b1, b2, b3)      EMIT((b1) + ((b2) << 8) + ((b3) << 16), 3)
 #define EMIT4(b1, b2, b3, b4)   EMIT((b1) + ((b2) << 8) + ((b3) << 16) + ((b4) << 24), 4)
+#define EMIT5(b1, b2, b3, b4, b5) \
+       do { EMIT1(b1); EMIT4(b2, b3, b4, b5); } while (0)
 
 #define EMIT1_off32(b1, off) \
        do { EMIT1(b1); EMIT(off, 4); } while (0)
@@ -1522,6 +1524,23 @@ static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
                EMIT1(0x59); /* pop rcx */
                EMIT1(0x58); /* pop rax */
        }
+       /* Insert IBHF instruction */
+       if ((cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_LOOP) &&
+            cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) ||
+           (cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_HW) &&
+            IS_ENABLED(CONFIG_X86_64))) {
+               /*
+                * Add an Indirect Branch History Fence (IBHF). IBHF acts as a
+                * fence preventing branch history from before the fence from
+                * affecting indirect branches after the fence. This is
+                * specifically used in cBPF jitted code to prevent Intra-mode
+                * BHI attacks. The IBHF instruction is designed to be a NOP on
+                * hardware that doesn't need or support it.  The REP and REX.W
+                * prefixes are required by the microcode, and they also ensure
+                * that the NOP is unlikely to be used in existing code.
+                */
+               EMIT5(0xF3, 0x48, 0x0F, 0x1E, 0xF8); /* ibhf */
+       }
        *pprog = prog;
        return 0;
 }