Commit caf12fa9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'ibti-hisory-for-linus-2025-05-06' of...

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
parents 82f2b0b9 073fdbe0
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -1697,11 +1697,11 @@ static void __init bhi_select_mitigation(void)
			return;
	}

	/* Mitigate in hardware if supported */
	if (spec_ctrl_bhi_dis())
	if (!IS_ENABLED(CONFIG_X86_64))
		return;

	if (!IS_ENABLED(CONFIG_X86_64))
	/* Mitigate in hardware if supported */
	if (spec_ctrl_bhi_dis())
		return;

	if (bhi_mitigation == BHI_MITIGATION_VMEXIT_ONLY) {
+6 −3
Original line number Diff line number Diff line
@@ -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);
+51 −0
Original line number Diff line number Diff line
@@ -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)
@@ -1502,6 +1504,48 @@ static void emit_priv_frame_ptr(u8 **pprog, void __percpu *priv_frame_ptr)
#define PRIV_STACK_GUARD_SZ    8
#define PRIV_STACK_GUARD_VAL   0xEB9F12345678eb9fULL

static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
				    struct bpf_prog *bpf_prog)
{
	u8 *prog = *pprog;
	u8 *func;

	if (cpu_feature_enabled(X86_FEATURE_CLEAR_BHB_LOOP)) {
		/* The clearing sequence clobbers eax and ecx. */
		EMIT1(0x50); /* push rax */
		EMIT1(0x51); /* push rcx */
		ip += 2;

		func = (u8 *)clear_bhb_loop;
		ip += x86_call_depth_emit_accounting(&prog, func, ip);

		if (emit_call(&prog, func, ip))
			return -EINVAL;
		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)) {
		/*
		 * 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.
		 *
		 * IBHF is not a valid instruction in 32-bit mode.
		 */
		EMIT5(0xF3, 0x48, 0x0F, 0x1E, 0xF8); /* ibhf */
	}
	*pprog = prog;
	return 0;
}

static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
		  int oldproglen, struct jit_context *ctx, bool jmp_padding)
{
@@ -2544,6 +2588,13 @@ st: if (is_imm8(insn->off))
			seen_exit = true;
			/* Update cleanup_addr */
			ctx->cleanup_addr = proglen;
			if (bpf_prog_was_classic(bpf_prog) &&
			    !capable(CAP_SYS_ADMIN)) {
				u8 *ip = image + addrs[i - 1];

				if (emit_spectre_bhb_barrier(&prog, ip, bpf_prog))
					return -EINVAL;
			}
			if (bpf_prog->aux->exception_boundary) {
				pop_callee_regs(&prog, all_callee_regs_used);
				pop_r12(&prog);