diff mbox series

[2/2] Adding BPF CFI

Message ID SEZPR03MB6786D49D9668F8F091598FA2B4602@SEZPR03MB6786.apcprd03.prod.outlook.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series [1/2] Adding BPF NX | expand

Checks

Context Check Description
netdev/tree_selection success Guessing tree name failed - patch did not apply
bpf/vmtest-bpf-PR success PR summary
bpf/vmtest-bpf-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-VM_Test-10 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-VM_Test-15 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-VM_Test-14 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-VM_Test-20 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-VM_Test-28 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-38 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-36 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18 and -O2 optimization
bpf/vmtest-bpf-VM_Test-23 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-26 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-31 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-21 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-19 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-VM_Test-35 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-34 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-27 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-16 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-VM_Test-42 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-VM_Test-39 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-33 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-VM_Test-25 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-41 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-VM_Test-13 success Logs for s390x-gcc / test (test_maps, false, 360) / test_maps on s390x with gcc
bpf/vmtest-bpf-VM_Test-29 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17 and -O2 optimization
bpf/vmtest-bpf-VM_Test-18 success Logs for set-matrix
bpf/vmtest-bpf-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-VM_Test-22 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-VM_Test-17 success Logs for s390x-gcc / veristat

Commit Message

Maxwell Bland Jan. 3, 2024, 7:17 p.m. UTC
From: Tenut <tenut@Niobium>
Subject: [PATCH 2/2] Adding BPF CFI

Check offset of BPF instructions in the interpreter to make sure the BPF program is executed from the correct starting point

Signed-off-by: Maxwell Bland <mbland@motorola.com>
---
kernel/bpf/Kconfig | 10 +++++++
 kernel/bpf/core.c  | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+)

 	bpf_insn_check_range(insn);
+	check_bpf_exec_mode();
 	goto *jumptable[insn->code];
 
 	/* Explicitly mask the register-based shift amounts with 63 or 31 @@ -2034,6 +2110,9 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn)
 		insn += insn->imm;
 		CONT;
 	JMP_EXIT:
+#ifdef CONFIG_BPF_CFI
+		leave_bpf_exec_mode(&flags);
+#endif
 		return BPF_R0;
 	/* JMP */
 #define COND_JMP(SIGN, OPCODE, CMP_OP)				\
diff mbox series

Patch

diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig index 7160dcaaa58a..9c64db0ddd63 100644
--- a/kernel/bpf/Kconfig
+++ b/kernel/bpf/Kconfig
@@ -94,6 +94,7 @@  config BPF_HARDENING
 	help
 	  Enhance bpf interpreter's security
 
+if BPF_HARDENING
 config BPF_NX
 bool "Enable bpf NX"
 	depends on BPF_HARDENING && !DYNAMIC_MEMORY_LAYOUT @@ -102,6 +103,15 @@ bool "Enable bpf NX"
 	  Allocate eBPF programs in seperate area and make sure the
 	  interpreted programs are in the region.
 
+config BPF_CFI
+	bool "Enable bpf CFI"
+	depends on BPF_NX
+	default n
+	help
+	  Enable alignment checks for eBPF program starting points
+
+endif
+
 source "kernel/bpf/preload/Kconfig"
 
 config BPF_LSM
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 56d9e8d4a6de..dee0d2713c3b 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -116,6 +116,75 @@  static void bpf_insn_check_range(const struct bpf_insn *insn)  }  #endif /* CONFIG_BPF_NX */
 
+#ifdef CONFIG_BPF_CFI
+#define BPF_ON  1
+#define BPF_OFF 0
+
+struct bpf_mode_flag {
+	u8 byte_array[PAGE_SIZE];
+};
+DEFINE_PER_CPU_PAGE_ALIGNED(struct bpf_mode_flag, bpf_exec_mode);
+
+static void __init lock_bpf_exec_mode(void) {
+	struct bpf_mode_flag *flag_page;
+	int cpu;
+	for_each_possible_cpu(cpu) {
+		flag_page = per_cpu_ptr(&bpf_exec_mode, cpu);
+		set_memory_ro((unsigned long)flag_page, 1);
+	};
+}
+subsys_initcall(lock_bpf_exec_mode);
+
+static void write_cr0_nocheck(unsigned long val) {
+	asm volatile("mov %0,%%cr0": "+r" (val) : : "memory"); }
+
+/*
+ * Notice that get_cpu_var also disables preemption so no
+ * extra care needed for that.
+ */
+static void enter_bpf_exec_mode(unsigned long *flagsp) {
+	struct bpf_mode_flag *flag_page;
+	flag_page = &get_cpu_var(bpf_exec_mode);
+	local_irq_save(*flagsp);
+	write_cr0_nocheck(read_cr0() & ~X86_CR0_WP);
+	flag_page->byte_array[0] = BPF_ON;
+	write_cr0_nocheck(read_cr0() | X86_CR0_WP); }
+
+static void leave_bpf_exec_mode(unsigned long *flagsp) {
+	struct bpf_mode_flag *flag_page;
+	flag_page = this_cpu_ptr(&bpf_exec_mode);
+	write_cr0_nocheck(read_cr0() & ~X86_CR0_WP);
+	flag_page->byte_array[0] = BPF_OFF;
+	write_cr0_nocheck(read_cr0() | X86_CR0_WP);
+	local_irq_restore(*flagsp);
+	put_cpu_var(bpf_exec_mode);
+}
+
+static void check_bpf_exec_mode(void)
+{
+	struct bpf_mode_flag *flag_page;
+	flag_page = this_cpu_ptr(&bpf_exec_mode);
+	BUG_ON(flag_page->byte_array[0] != BPF_ON); }
+
+static void bpf_check_cfi(const struct bpf_insn *insn) {
+	const struct bpf_prog *fp;
+	fp = container_of(insn, struct bpf_prog, insnsi[0]);
+	if (!IS_ALIGNED((unsigned long)fp, BPF_MEMORY_ALIGN))
+		BUG();
+}
+
+#else /* CONFIG_BPF_CFI */
+static void check_bpf_exec_mode(void) {} #endif /* CONFIG_BPF_CFI */
+
 struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flags)  {
 	gfp_t gfp_flags = bpf_memcg_flags(GFP_KERNEL | __GFP_ZERO | gfp_extra_flags); @@ -1719,11 +1788,18 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn)  #undef BPF_INSN_2_LBL
 	u32 tail_call_cnt = 0;
 
+#ifdef CONFIG_BPF_CFI
+	unsigned long flags;
+	enter_bpf_exec_mode(&flags);
+	bpf_check_cfi(insn);
+#endif
+
 #define CONT	 ({ insn++; goto select_insn; })
 #define CONT_JMP ({ insn++; goto select_insn; })
 
 select_insn: