]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/bpf: Add tests for stack argument validation
authorYonghong Song <yonghong.song@linux.dev>
Wed, 13 May 2026 04:51:32 +0000 (21:51 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 13 May 2026 16:27:32 +0000 (09:27 -0700)
Add negative tests that verify the kfunc (rejecting kfunc call
with >8 byte struct as stack argument) and the verifier
(rejecting invalid uses of r11 for stack arguments).

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/r/20260513045132.2398371-1-yonghong.song@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/prog_tests/stack_arg_fail.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/stack_arg_fail.c [new file with mode: 0644]
tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h

diff --git a/tools/testing/selftests/bpf/prog_tests/stack_arg_fail.c b/tools/testing/selftests/bpf/prog_tests/stack_arg_fail.c
new file mode 100644 (file)
index 0000000..090af13
--- /dev/null
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+
+#include <test_progs.h>
+#include "stack_arg_fail.skel.h"
+
+void test_stack_arg_fail(void)
+{
+       RUN_TESTS(stack_arg_fail);
+}
diff --git a/tools/testing/selftests/bpf/progs/stack_arg_fail.c b/tools/testing/selftests/bpf/progs/stack_arg_fail.c
new file mode 100644 (file)
index 0000000..ad9d4bf
--- /dev/null
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "../test_kmods/bpf_testmod_kfunc.h"
+#include "bpf_misc.h"
+
+#if defined(__BPF_FEATURE_STACK_ARGUMENT)
+
+SEC("tc")
+__failure __msg("Unrecognized *(R11-8) type STRUCT")
+int test_stack_arg_big(struct __sk_buff *skb)
+{
+       struct prog_test_big_arg s = { .a = 1, .b = 2 };
+
+       return bpf_kfunc_call_stack_arg_big(1, 2, 3, 4, 5, s);
+}
+
+SEC("socket")
+__description("r11 in ALU instruction")
+__failure __msg("R11 is invalid")
+__naked void r11_alu_reject(void)
+{
+       asm volatile (
+       "r11 += 1;"
+       "r0 = 0;"
+       "exit;"
+       ::: __clobber_all);
+}
+
+SEC("socket")
+__description("r11 store with non-DW size")
+__failure __msg("R11 is invalid")
+__naked void r11_store_non_dw(void)
+{
+       asm volatile (
+       "*(u32 *)(r11 - 8) = r1;"
+       "r0 = 0;"
+       "exit;"
+       ::: __clobber_all);
+}
+
+SEC("socket")
+__description("r11 store with unaligned offset")
+__failure __msg("R11 is invalid")
+__naked void r11_store_unaligned(void)
+{
+       asm volatile (
+       "*(u64 *)(r11 - 4) = r1;"
+       "r0 = 0;"
+       "exit;"
+       ::: __clobber_all);
+}
+
+SEC("socket")
+__description("r11 store with positive offset")
+__failure __msg("R11 is invalid")
+__naked void r11_store_positive_off(void)
+{
+       asm volatile (
+       "*(u64 *)(r11 + 8) = r1;"
+       "r0 = 0;"
+       "exit;"
+       ::: __clobber_all);
+}
+
+SEC("socket")
+__description("r11 load with negative offset")
+__failure __msg("R11 is invalid")
+__naked void r11_load_negative_off(void)
+{
+       asm volatile (
+       "r0 = *(u64 *)(r11 - 8);"
+       "exit;"
+       ::: __clobber_all);
+}
+
+SEC("socket")
+__description("r11 load with non-DW size")
+__failure __msg("R11 is invalid")
+__naked void r11_load_non_dw(void)
+{
+       asm volatile (
+       "r0 = *(u32 *)(r11 + 8);"
+       "exit;"
+       ::: __clobber_all);
+}
+
+SEC("socket")
+__description("r11 store with zero offset")
+__failure __msg("R11 is invalid")
+__naked void r11_store_zero_off(void)
+{
+       asm volatile (
+       "*(u64 *)(r11 + 0) = r1;"
+       "r0 = 0;"
+       "exit;"
+       ::: __clobber_all);
+}
+
+#else
+
+SEC("tc")
+__description("stack_arg_fail: not supported, dummy test")
+__success
+int test_stack_arg_big(struct __sk_buff *skb)
+{
+       return 0;
+}
+
+#endif
+
+char _license[] SEC("license") = "GPL";
index aef2f68b7e8332cbbd373a0df4b5b558adefdaba..0be918fe30216d6e1f061447250c09a2e7f2c8b8 100644 (file)
@@ -882,6 +882,12 @@ __bpf_kfunc u64 bpf_kfunc_call_stack_arg_timer(u64 a, u64 b, u64 c, u64 d, u64 e
        return a + b + c + d + e;
 }
 
+__bpf_kfunc u64 bpf_kfunc_call_stack_arg_big(u64 a, u64 b, u64 c, u64 d, u64 e,
+                                            struct prog_test_big_arg s)
+{
+       return a + b + c + d + e + s.a + s.b;
+}
+
 static struct prog_test_ref_kfunc prog_test_struct = {
        .a = 42,
        .b = 108,
@@ -1353,6 +1359,7 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_stack_arg_mem)
 BTF_ID_FLAGS(func, bpf_kfunc_call_stack_arg_iter)
 BTF_ID_FLAGS(func, bpf_kfunc_call_stack_arg_const_str)
 BTF_ID_FLAGS(func, bpf_kfunc_call_stack_arg_timer)
+BTF_ID_FLAGS(func, bpf_kfunc_call_stack_arg_big)
 BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail1)
 BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail2)
 BTF_ID_FLAGS(func, bpf_kfunc_call_test_acquire, KF_ACQUIRE | KF_RET_NULL)
index 2c1cb118f88672cef0e1caa41a933b0fcbb7b622..2edc36b66de9d6c24d9b897c6fc6254b4bc3d458 100644 (file)
@@ -50,6 +50,11 @@ struct prog_test_pass2 {
        } x;
 };
 
+struct prog_test_big_arg {
+       __u64 a;
+       __u64 b;
+};
+
 struct prog_test_fail1 {
        void *p;
        int x;
@@ -130,6 +135,9 @@ __u64 bpf_kfunc_call_stack_arg_const_str(__u64 a, __u64 b, __u64 c, __u64 d, __u
                                         const char *str__str) __ksym;
 __u64 bpf_kfunc_call_stack_arg_timer(__u64 a, __u64 b, __u64 c, __u64 d, __u64 e,
                                     struct bpf_timer *timer) __ksym;
+__u64 bpf_kfunc_call_stack_arg_big(__u64 a, __u64 b, __u64 c, __u64 d, __u64 e,
+                                  struct prog_test_big_arg s) __ksym;
+
 void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym;
 void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym;
 void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym;