]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf, x86: Add x86 JIT support for timed may_goto
authorKumar Kartikeya Dwivedi <memxor@gmail.com>
Tue, 4 Mar 2025 00:32:39 +0000 (16:32 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 15 Mar 2025 18:48:28 +0000 (11:48 -0700)
Implement the arch_bpf_timed_may_goto function using inline assembly to
have control over which registers are spilled, and use our special
protocol of using BPF_REG_AX as an argument into the function, and as
the return value when going back.

Emit call depth accounting for the call made from this stub, and ensure
we don't have naked returns (when rethunk mitigations are enabled) by
falling back to the RET macro (instead of retq). After popping all saved
registers, the return address into the BPF program should be on top of
the stack.

Since the JIT support is now enabled, ensure selftests which are
checking the produced may_goto sequences do not break by adjusting them.
Make sure we still test the old may_goto sequence on other
architectures, while testing the new sequence on x86_64.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20250304003239.2390751-3-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
arch/x86/net/Makefile
arch/x86/net/bpf_jit_comp.c
arch/x86/net/bpf_timed_may_goto.S [new file with mode: 0644]
tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
tools/testing/selftests/bpf/progs/verifier_may_goto_1.c

index 383c87300b0d31869ea3980d36a1694202c09ef3..dddbefc0f4398ac58946701e94114ca44a9310e5 100644 (file)
@@ -6,5 +6,5 @@
 ifeq ($(CONFIG_X86_32),y)
         obj-$(CONFIG_BPF_JIT) += bpf_jit_comp32.o
 else
-        obj-$(CONFIG_BPF_JIT) += bpf_jit_comp.o
+        obj-$(CONFIG_BPF_JIT) += bpf_jit_comp.o bpf_timed_may_goto.o
 endif
index a43fc5af973d27676baee38dd6b080a14c3a0bb5..f3e9ef6b5329cb82f25e0303491645ce68b5d932 100644 (file)
@@ -3791,3 +3791,8 @@ u64 bpf_arch_uaddress_limit(void)
 {
        return 0;
 }
+
+bool bpf_jit_supports_timed_may_goto(void)
+{
+       return true;
+}
diff --git a/arch/x86/net/bpf_timed_may_goto.S b/arch/x86/net/bpf_timed_may_goto.S
new file mode 100644 (file)
index 0000000..20de4a1
--- /dev/null
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
+
+#include <linux/export.h>
+#include <linux/linkage.h>
+#include <asm/nospec-branch.h>
+
+       .code64
+       .section .text, "ax"
+
+SYM_FUNC_START(arch_bpf_timed_may_goto)
+       ANNOTATE_NOENDBR
+
+       /* Save r0-r5. */
+       pushq %rax
+       pushq %rdi
+       pushq %rsi
+       pushq %rdx
+       pushq %rcx
+       pushq %r8
+
+       /*
+        * r10 passes us stack depth, load the pointer to count and timestamp as
+        * first argument to the call below.
+        */
+       leaq (%rbp, %r10, 1), %rdi
+
+       /* Emit call depth accounting for call below. */
+       CALL_DEPTH_ACCOUNT
+       call bpf_check_timed_may_goto
+
+       /* BPF_REG_AX=r10 will be stored into count, so move return value to it. */
+       movq %rax, %r10
+
+       /* Restore r5-r0. */
+       popq %r8
+       popq %rcx
+       popq %rdx
+       popq %rsi
+       popq %rdi
+       popq %rax
+
+       RET
+SYM_FUNC_END(arch_bpf_timed_may_goto)
index 5094c288cfd7bc889199fcb8234088bda3437ac5..a9be6ae49454564b7a0f2b417e248ccad6d8e642 100644 (file)
@@ -620,23 +620,61 @@ __naked void helper_call_does_not_prevent_bpf_fastcall(void)
 
 SEC("raw_tp")
 __arch_x86_64
+__log_level(4) __msg("stack depth 24")
+/* may_goto counter at -24 */
+__xlated("0: *(u64 *)(r10 -24) =")
+/* may_goto timestamp at -16 */
+__xlated("1: *(u64 *)(r10 -16) =")
+__xlated("2: r1 = 1")
+__xlated("...")
+__xlated("4: r0 = &(void __percpu *)(r0)")
+__xlated("...")
+/* may_goto expansion starts */
+__xlated("6: r11 = *(u64 *)(r10 -24)")
+__xlated("7: if r11 == 0x0 goto pc+6")
+__xlated("8: r11 -= 1")
+__xlated("9: if r11 != 0x0 goto pc+2")
+__xlated("10: r11 = -24")
+__xlated("11: call unknown")
+__xlated("12: *(u64 *)(r10 -24) = r11")
+/* may_goto expansion ends */
+__xlated("13: *(u64 *)(r10 -8) = r1")
+__xlated("14: exit")
+__success
+__naked void may_goto_interaction_x86_64(void)
+{
+       asm volatile (
+       "r1 = 1;"
+       "*(u64 *)(r10 - 16) = r1;"
+       "call %[bpf_get_smp_processor_id];"
+       "r1 = *(u64 *)(r10 - 16);"
+       ".8byte %[may_goto];"
+       /* just touch some stack at -8 */
+       "*(u64 *)(r10 - 8) = r1;"
+       "exit;"
+       :
+       : __imm(bpf_get_smp_processor_id),
+         __imm_insn(may_goto, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, +1 /* offset */, 0))
+       : __clobber_all);
+}
+
+SEC("raw_tp")
+__arch_arm64
 __log_level(4) __msg("stack depth 16")
 /* may_goto counter at -16 */
 __xlated("0: *(u64 *)(r10 -16) =")
 __xlated("1: r1 = 1")
-__xlated("...")
-__xlated("3: r0 = &(void __percpu *)(r0)")
-__xlated("...")
+__xlated("2: call bpf_get_smp_processor_id")
 /* may_goto expansion starts */
-__xlated("5: r11 = *(u64 *)(r10 -16)")
-__xlated("6: if r11 == 0x0 goto pc+3")
-__xlated("7: r11 -= 1")
-__xlated("8: *(u64 *)(r10 -16) = r11")
+__xlated("3: r11 = *(u64 *)(r10 -16)")
+__xlated("4: if r11 == 0x0 goto pc+3")
+__xlated("5: r11 -= 1")
+__xlated("6: *(u64 *)(r10 -16) = r11")
 /* may_goto expansion ends */
-__xlated("9: *(u64 *)(r10 -8) = r1")
-__xlated("10: exit")
+__xlated("7: *(u64 *)(r10 -8) = r1")
+__xlated("8: exit")
 __success
-__naked void may_goto_interaction(void)
+__naked void may_goto_interaction_arm64(void)
 {
        asm volatile (
        "r1 = 1;"
index e81097c96fe275ef4e6026809ce98d3317f34465..3966d827f28892a5a9a521e550e1dfafea5783cd 100644 (file)
@@ -69,8 +69,38 @@ __naked void may_goto_batch_1(void)
 }
 
 SEC("raw_tp")
-__description("may_goto batch with offsets 2/0")
+__description("may_goto batch with offsets 2/0 - x86_64")
 __arch_x86_64
+__xlated("0: *(u64 *)(r10 -16) = 65535")
+__xlated("1: *(u64 *)(r10 -8) = 0")
+__xlated("2: r11 = *(u64 *)(r10 -16)")
+__xlated("3: if r11 == 0x0 goto pc+6")
+__xlated("4: r11 -= 1")
+__xlated("5: if r11 != 0x0 goto pc+2")
+__xlated("6: r11 = -16")
+__xlated("7: call unknown")
+__xlated("8: *(u64 *)(r10 -16) = r11")
+__xlated("9: r0 = 1")
+__xlated("10: r0 = 2")
+__xlated("11: exit")
+__success
+__naked void may_goto_batch_2_x86_64(void)
+{
+       asm volatile (
+       ".8byte %[may_goto1];"
+       ".8byte %[may_goto3];"
+       "r0 = 1;"
+       "r0 = 2;"
+       "exit;"
+       :
+       : __imm_insn(may_goto1, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 2 /* offset */, 0)),
+         __imm_insn(may_goto3, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 0 /* offset */, 0))
+       : __clobber_all);
+}
+
+SEC("raw_tp")
+__description("may_goto batch with offsets 2/0 - arm64")
+__arch_arm64
 __xlated("0: *(u64 *)(r10 -8) = 8388608")
 __xlated("1: r11 = *(u64 *)(r10 -8)")
 __xlated("2: if r11 == 0x0 goto pc+3")
@@ -80,7 +110,7 @@ __xlated("5: r0 = 1")
 __xlated("6: r0 = 2")
 __xlated("7: exit")
 __success
-__naked void may_goto_batch_2(void)
+__naked void may_goto_batch_2_arm64(void)
 {
        asm volatile (
        ".8byte %[may_goto1];"