* [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic
@ 2023-02-16 4:59 Andrii Nakryiko
2023-02-16 4:59 ` [PATCH v2 bpf-next 1/3] bpf: fix global subprog context argument resolution logic Andrii Nakryiko
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Andrii Nakryiko @ 2023-02-16 4:59 UTC (permalink / raw)
To: bpf, ast, daniel; +Cc: andrii, kernel-team
Fix kernel bug in determining whether global subprog's argument is PTR_TO_CTX,
which is done based on type names. Currently KPROBE programs are broken.
Add few tests validating that KPROBE context can be passed to global subprog.
For that also refactor test_global_funcs test to use test_loader framework.
v1->v2:
- fix compilation warning on arm64 and s390x by force-casting ctx to
`void *`, to discard const from `const struct user_pt_regs *`, when
passing it to bpf_get_stack().
Andrii Nakryiko (3):
bpf: fix global subprog context argument resolution logic
selftests/bpf: convert test_global_funcs test to test_loader framework
selftests/bpf: add global subprog context passing tests
kernel/bpf/btf.c | 13 +-
.../bpf/prog_tests/test_global_funcs.c | 133 +++++-------------
.../selftests/bpf/progs/test_global_func1.c | 6 +-
.../selftests/bpf/progs/test_global_func10.c | 4 +-
.../selftests/bpf/progs/test_global_func11.c | 4 +-
.../selftests/bpf/progs/test_global_func12.c | 4 +-
.../selftests/bpf/progs/test_global_func13.c | 4 +-
.../selftests/bpf/progs/test_global_func14.c | 4 +-
.../selftests/bpf/progs/test_global_func15.c | 4 +-
.../selftests/bpf/progs/test_global_func16.c | 4 +-
.../selftests/bpf/progs/test_global_func17.c | 4 +-
.../selftests/bpf/progs/test_global_func2.c | 43 +++++-
.../selftests/bpf/progs/test_global_func3.c | 10 +-
.../selftests/bpf/progs/test_global_func4.c | 55 +++++++-
.../selftests/bpf/progs/test_global_func5.c | 4 +-
.../selftests/bpf/progs/test_global_func6.c | 4 +-
.../selftests/bpf/progs/test_global_func7.c | 4 +-
.../selftests/bpf/progs/test_global_func8.c | 4 +-
.../selftests/bpf/progs/test_global_func9.c | 4 +-
.../bpf/progs/test_global_func_ctx_args.c | 105 ++++++++++++++
20 files changed, 292 insertions(+), 125 deletions(-)
create mode 100644 tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c
--
2.30.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 bpf-next 1/3] bpf: fix global subprog context argument resolution logic
2023-02-16 4:59 [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic Andrii Nakryiko
@ 2023-02-16 4:59 ` Andrii Nakryiko
2023-02-16 4:59 ` [PATCH v2 bpf-next 2/3] selftests/bpf: convert test_global_funcs test to test_loader framework Andrii Nakryiko
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Andrii Nakryiko @ 2023-02-16 4:59 UTC (permalink / raw)
To: bpf, ast, daniel; +Cc: andrii, kernel-team
KPROBE program's user-facing context type is defined as typedef
bpf_user_pt_regs_t. This leads to a problem when trying to passing
kprobe/uprobe/usdt context argument into global subprog, as kernel
always strip away mods and typedefs of user-supplied type, but takes
expected type from bpf_ctx_convert as is, which causes mismatch.
Current way to work around this is to define a fake struct with the same
name as expected typedef:
struct bpf_user_pt_regs_t {};
__noinline my_global_subprog(struct bpf_user_pt_regs_t *ctx) { ... }
This patch fixes the issue by resolving expected type, if it's not
a struct. It still leaves the above work-around working for backwards
compatibility.
Fixes: 91cc1a99740e ("bpf: Annotate context types")
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
kernel/bpf/btf.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 6582735ef1fc..fa22ec79ac0e 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -5669,6 +5669,7 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
if (!ctx_struct)
/* should not happen */
return NULL;
+again:
ctx_tname = btf_name_by_offset(btf_vmlinux, ctx_struct->name_off);
if (!ctx_tname) {
/* should not happen */
@@ -5682,8 +5683,16 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
* int socket_filter_bpf_prog(struct __sk_buff *skb)
* { // no fields of skb are ever used }
*/
- if (strcmp(ctx_tname, tname))
- return NULL;
+ if (strcmp(ctx_tname, tname)) {
+ /* bpf_user_pt_regs_t is a typedef, so resolve it to
+ * underlying struct and check name again
+ */
+ if (!btf_type_is_modifier(ctx_struct))
+ return NULL;
+ while (btf_type_is_modifier(ctx_struct))
+ ctx_struct = btf_type_by_id(btf_vmlinux, ctx_struct->type);
+ goto again;
+ }
return ctx_type;
}
--
2.30.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 bpf-next 2/3] selftests/bpf: convert test_global_funcs test to test_loader framework
2023-02-16 4:59 [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic Andrii Nakryiko
2023-02-16 4:59 ` [PATCH v2 bpf-next 1/3] bpf: fix global subprog context argument resolution logic Andrii Nakryiko
@ 2023-02-16 4:59 ` Andrii Nakryiko
2023-02-16 4:59 ` [PATCH v2 bpf-next 3/3] selftests/bpf: add global subprog context passing tests Andrii Nakryiko
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Andrii Nakryiko @ 2023-02-16 4:59 UTC (permalink / raw)
To: bpf, ast, daniel; +Cc: andrii, kernel-team
Convert 17 test_global_funcs subtests into test_loader framework for
easier maintenance and more declarative way to define expected
failures/successes.
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
.../bpf/prog_tests/test_global_funcs.c | 131 +++++-------------
.../selftests/bpf/progs/test_global_func1.c | 6 +-
.../selftests/bpf/progs/test_global_func10.c | 4 +-
.../selftests/bpf/progs/test_global_func11.c | 4 +-
.../selftests/bpf/progs/test_global_func12.c | 4 +-
.../selftests/bpf/progs/test_global_func13.c | 4 +-
.../selftests/bpf/progs/test_global_func14.c | 4 +-
.../selftests/bpf/progs/test_global_func15.c | 4 +-
.../selftests/bpf/progs/test_global_func16.c | 4 +-
.../selftests/bpf/progs/test_global_func17.c | 4 +-
.../selftests/bpf/progs/test_global_func2.c | 43 +++++-
.../selftests/bpf/progs/test_global_func3.c | 10 +-
.../selftests/bpf/progs/test_global_func4.c | 55 +++++++-
.../selftests/bpf/progs/test_global_func5.c | 4 +-
.../selftests/bpf/progs/test_global_func6.c | 4 +-
.../selftests/bpf/progs/test_global_func7.c | 4 +-
.../selftests/bpf/progs/test_global_func8.c | 4 +-
.../selftests/bpf/progs/test_global_func9.c | 4 +-
18 files changed, 174 insertions(+), 123 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c b/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c
index 7295cc60f724..2ff4d5c7abfc 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c
@@ -1,104 +1,41 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */
#include <test_progs.h>
-
-const char *err_str;
-bool found;
-
-static int libbpf_debug_print(enum libbpf_print_level level,
- const char *format, va_list args)
-{
- char *log_buf;
-
- if (level != LIBBPF_WARN ||
- strcmp(format, "libbpf: \n%s\n")) {
- vprintf(format, args);
- return 0;
- }
-
- log_buf = va_arg(args, char *);
- if (!log_buf)
- goto out;
- if (err_str && strstr(log_buf, err_str) == 0)
- found = true;
-out:
- printf(format, log_buf);
- return 0;
-}
-
-extern int extra_prog_load_log_flags;
-
-static int check_load(const char *file)
-{
- struct bpf_object *obj = NULL;
- struct bpf_program *prog;
- int err;
-
- found = false;
-
- obj = bpf_object__open_file(file, NULL);
- err = libbpf_get_error(obj);
- if (err)
- return err;
-
- prog = bpf_object__next_program(obj, NULL);
- if (!prog) {
- err = -ENOENT;
- goto err_out;
- }
-
- bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32);
- bpf_program__set_log_level(prog, extra_prog_load_log_flags);
-
- err = bpf_object__load(obj);
-
-err_out:
- bpf_object__close(obj);
- return err;
-}
-
-struct test_def {
- const char *file;
- const char *err_str;
-};
+#include "test_global_func1.skel.h"
+#include "test_global_func2.skel.h"
+#include "test_global_func3.skel.h"
+#include "test_global_func4.skel.h"
+#include "test_global_func5.skel.h"
+#include "test_global_func6.skel.h"
+#include "test_global_func7.skel.h"
+#include "test_global_func8.skel.h"
+#include "test_global_func9.skel.h"
+#include "test_global_func10.skel.h"
+#include "test_global_func11.skel.h"
+#include "test_global_func12.skel.h"
+#include "test_global_func13.skel.h"
+#include "test_global_func14.skel.h"
+#include "test_global_func15.skel.h"
+#include "test_global_func16.skel.h"
+#include "test_global_func17.skel.h"
void test_test_global_funcs(void)
{
- struct test_def tests[] = {
- { "test_global_func1.bpf.o", "combined stack size of 4 calls is 544" },
- { "test_global_func2.bpf.o" },
- { "test_global_func3.bpf.o", "the call stack of 8 frames" },
- { "test_global_func4.bpf.o" },
- { "test_global_func5.bpf.o", "expected pointer to ctx, but got PTR" },
- { "test_global_func6.bpf.o", "modified ctx ptr R2" },
- { "test_global_func7.bpf.o", "foo() doesn't return scalar" },
- { "test_global_func8.bpf.o" },
- { "test_global_func9.bpf.o" },
- { "test_global_func10.bpf.o", "invalid indirect read from stack" },
- { "test_global_func11.bpf.o", "Caller passes invalid args into func#1" },
- { "test_global_func12.bpf.o", "invalid mem access 'mem_or_null'" },
- { "test_global_func13.bpf.o", "Caller passes invalid args into func#1" },
- { "test_global_func14.bpf.o", "reference type('FWD S') size cannot be determined" },
- { "test_global_func15.bpf.o", "At program exit the register R0 has value" },
- { "test_global_func16.bpf.o", "invalid indirect read from stack" },
- { "test_global_func17.bpf.o", "Caller passes invalid args into func#1" },
- };
- libbpf_print_fn_t old_print_fn = NULL;
- int err, i, duration = 0;
-
- old_print_fn = libbpf_set_print(libbpf_debug_print);
-
- for (i = 0; i < ARRAY_SIZE(tests); i++) {
- const struct test_def *test = &tests[i];
-
- if (!test__start_subtest(test->file))
- continue;
-
- err_str = test->err_str;
- err = check_load(test->file);
- CHECK_FAIL(!!err ^ !!err_str);
- if (err_str)
- CHECK(found, "", "expected string '%s'", err_str);
- }
- libbpf_set_print(old_print_fn);
+ RUN_TESTS(test_global_func1);
+ RUN_TESTS(test_global_func2);
+ RUN_TESTS(test_global_func3);
+ RUN_TESTS(test_global_func4);
+ RUN_TESTS(test_global_func5);
+ RUN_TESTS(test_global_func6);
+ RUN_TESTS(test_global_func7);
+ RUN_TESTS(test_global_func8);
+ RUN_TESTS(test_global_func9);
+ RUN_TESTS(test_global_func10);
+ RUN_TESTS(test_global_func11);
+ RUN_TESTS(test_global_func12);
+ RUN_TESTS(test_global_func13);
+ RUN_TESTS(test_global_func14);
+ RUN_TESTS(test_global_func15);
+ RUN_TESTS(test_global_func16);
+ RUN_TESTS(test_global_func17);
}
diff --git a/tools/testing/selftests/bpf/progs/test_global_func1.c b/tools/testing/selftests/bpf/progs/test_global_func1.c
index 7b42dad187b8..23970a20b324 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func1.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func1.c
@@ -3,10 +3,9 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
-#ifndef MAX_STACK
#define MAX_STACK (512 - 3 * 32 + 8)
-#endif
static __attribute__ ((noinline))
int f0(int var, struct __sk_buff *skb)
@@ -39,7 +38,8 @@ int f3(int val, struct __sk_buff *skb, int var)
}
SEC("tc")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("combined stack size of 4 calls is 544")
+int global_func1(struct __sk_buff *skb)
{
return f0(1, skb) + f1(skb) + f2(2, skb) + f3(3, skb, 4);
}
diff --git a/tools/testing/selftests/bpf/progs/test_global_func10.c b/tools/testing/selftests/bpf/progs/test_global_func10.c
index 97b7031d0e22..98327bdbbfd2 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func10.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func10.c
@@ -2,6 +2,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
struct Small {
int x;
@@ -21,7 +22,8 @@ __noinline int foo(const struct Big *big)
}
SEC("cgroup_skb/ingress")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("invalid indirect read from stack")
+int global_func10(struct __sk_buff *skb)
{
const struct Small small = {.x = skb->len };
diff --git a/tools/testing/selftests/bpf/progs/test_global_func11.c b/tools/testing/selftests/bpf/progs/test_global_func11.c
index ef5277d982d9..283e036dc401 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func11.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func11.c
@@ -2,6 +2,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
struct S {
int x;
@@ -13,7 +14,8 @@ __noinline int foo(const struct S *s)
}
SEC("cgroup_skb/ingress")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("Caller passes invalid args into func#1")
+int global_func11(struct __sk_buff *skb)
{
return foo((const void *)skb);
}
diff --git a/tools/testing/selftests/bpf/progs/test_global_func12.c b/tools/testing/selftests/bpf/progs/test_global_func12.c
index 62343527cc59..7f159d83c6f6 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func12.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func12.c
@@ -2,6 +2,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
struct S {
int x;
@@ -13,7 +14,8 @@ __noinline int foo(const struct S *s)
}
SEC("cgroup_skb/ingress")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("invalid mem access 'mem_or_null'")
+int global_func12(struct __sk_buff *skb)
{
const struct S s = {.x = skb->len };
diff --git a/tools/testing/selftests/bpf/progs/test_global_func13.c b/tools/testing/selftests/bpf/progs/test_global_func13.c
index ff8897c1ac22..02ea80da75b5 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func13.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func13.c
@@ -2,6 +2,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
struct S {
int x;
@@ -16,7 +17,8 @@ __noinline int foo(const struct S *s)
}
SEC("cgroup_skb/ingress")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("Caller passes invalid args into func#1")
+int global_func13(struct __sk_buff *skb)
{
const struct S *s = (const struct S *)(0xbedabeda);
diff --git a/tools/testing/selftests/bpf/progs/test_global_func14.c b/tools/testing/selftests/bpf/progs/test_global_func14.c
index 698c77199ebf..33b7d5efd7b2 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func14.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func14.c
@@ -2,6 +2,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
struct S;
@@ -14,7 +15,8 @@ __noinline int foo(const struct S *s)
}
SEC("cgroup_skb/ingress")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("reference type('FWD S') size cannot be determined")
+int global_func14(struct __sk_buff *skb)
{
return foo(NULL);
diff --git a/tools/testing/selftests/bpf/progs/test_global_func15.c b/tools/testing/selftests/bpf/progs/test_global_func15.c
index c19c435988d5..b512d6a6c75e 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func15.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func15.c
@@ -2,6 +2,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
__noinline int foo(unsigned int *v)
{
@@ -12,7 +13,8 @@ __noinline int foo(unsigned int *v)
}
SEC("cgroup_skb/ingress")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("At program exit the register R0 has value")
+int global_func15(struct __sk_buff *skb)
{
unsigned int v = 1;
diff --git a/tools/testing/selftests/bpf/progs/test_global_func16.c b/tools/testing/selftests/bpf/progs/test_global_func16.c
index 0312d1e8d8c0..e7206304632e 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func16.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func16.c
@@ -2,6 +2,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
__noinline int foo(int (*arr)[10])
{
@@ -12,7 +13,8 @@ __noinline int foo(int (*arr)[10])
}
SEC("cgroup_skb/ingress")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("invalid indirect read from stack")
+int global_func16(struct __sk_buff *skb)
{
int array[10];
diff --git a/tools/testing/selftests/bpf/progs/test_global_func17.c b/tools/testing/selftests/bpf/progs/test_global_func17.c
index 2b8b9b8ba018..a32e11c7d933 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func17.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func17.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
__noinline int foo(int *p)
{
@@ -10,7 +11,8 @@ __noinline int foo(int *p)
const volatile int i;
SEC("tc")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("Caller passes invalid args into func#1")
+int global_func17(struct __sk_buff *skb)
{
return foo((int *)&i);
}
diff --git a/tools/testing/selftests/bpf/progs/test_global_func2.c b/tools/testing/selftests/bpf/progs/test_global_func2.c
index 2c18d82923a2..3dce97fb52a4 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func2.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func2.c
@@ -1,4 +1,45 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2020 Facebook */
+#include <stddef.h>
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
#define MAX_STACK (512 - 3 * 32)
-#include "test_global_func1.c"
+
+static __attribute__ ((noinline))
+int f0(int var, struct __sk_buff *skb)
+{
+ return skb->len;
+}
+
+__attribute__ ((noinline))
+int f1(struct __sk_buff *skb)
+{
+ volatile char buf[MAX_STACK] = {};
+
+ return f0(0, skb) + skb->len;
+}
+
+int f3(int, struct __sk_buff *skb, int);
+
+__attribute__ ((noinline))
+int f2(int val, struct __sk_buff *skb)
+{
+ return f1(skb) + f3(val, skb, 1);
+}
+
+__attribute__ ((noinline))
+int f3(int val, struct __sk_buff *skb, int var)
+{
+ volatile char buf[MAX_STACK] = {};
+
+ return skb->ifindex * val * var;
+}
+
+SEC("tc")
+__success
+int global_func2(struct __sk_buff *skb)
+{
+ return f0(1, skb) + f1(skb) + f2(2, skb) + f3(3, skb, 4);
+}
diff --git a/tools/testing/selftests/bpf/progs/test_global_func3.c b/tools/testing/selftests/bpf/progs/test_global_func3.c
index 01bf8275dfd6..142b682d3c2f 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func3.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func3.c
@@ -3,6 +3,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
__attribute__ ((noinline))
int f1(struct __sk_buff *skb)
@@ -46,20 +47,15 @@ int f7(struct __sk_buff *skb)
return f6(skb);
}
-#ifndef NO_FN8
__attribute__ ((noinline))
int f8(struct __sk_buff *skb)
{
return f7(skb);
}
-#endif
SEC("tc")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("the call stack of 8 frames")
+int global_func3(struct __sk_buff *skb)
{
-#ifndef NO_FN8
return f8(skb);
-#else
- return f7(skb);
-#endif
}
diff --git a/tools/testing/selftests/bpf/progs/test_global_func4.c b/tools/testing/selftests/bpf/progs/test_global_func4.c
index 610f75edf276..1733d87ad3f3 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func4.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func4.c
@@ -1,4 +1,55 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2020 Facebook */
-#define NO_FN8
-#include "test_global_func3.c"
+#include <stddef.h>
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+__attribute__ ((noinline))
+int f1(struct __sk_buff *skb)
+{
+ return skb->len;
+}
+
+__attribute__ ((noinline))
+int f2(int val, struct __sk_buff *skb)
+{
+ return f1(skb) + val;
+}
+
+__attribute__ ((noinline))
+int f3(int val, struct __sk_buff *skb, int var)
+{
+ return f2(var, skb) + val;
+}
+
+__attribute__ ((noinline))
+int f4(struct __sk_buff *skb)
+{
+ return f3(1, skb, 2);
+}
+
+__attribute__ ((noinline))
+int f5(struct __sk_buff *skb)
+{
+ return f4(skb);
+}
+
+__attribute__ ((noinline))
+int f6(struct __sk_buff *skb)
+{
+ return f5(skb);
+}
+
+__attribute__ ((noinline))
+int f7(struct __sk_buff *skb)
+{
+ return f6(skb);
+}
+
+SEC("tc")
+__success
+int global_func4(struct __sk_buff *skb)
+{
+ return f7(skb);
+}
diff --git a/tools/testing/selftests/bpf/progs/test_global_func5.c b/tools/testing/selftests/bpf/progs/test_global_func5.c
index 9248d03e0d06..cc55aedaf82d 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func5.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func5.c
@@ -3,6 +3,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
__attribute__ ((noinline))
int f1(struct __sk_buff *skb)
@@ -25,7 +26,8 @@ int f3(int val, struct __sk_buff *skb)
}
SEC("tc")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("expected pointer to ctx, but got PTR")
+int global_func5(struct __sk_buff *skb)
{
return f1(skb) + f2(2, skb) + f3(3, skb);
}
diff --git a/tools/testing/selftests/bpf/progs/test_global_func6.c b/tools/testing/selftests/bpf/progs/test_global_func6.c
index af8c78bdfb25..46c38c8f2cf0 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func6.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func6.c
@@ -3,6 +3,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
__attribute__ ((noinline))
int f1(struct __sk_buff *skb)
@@ -25,7 +26,8 @@ int f3(int val, struct __sk_buff *skb)
}
SEC("tc")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("modified ctx ptr R2")
+int global_func6(struct __sk_buff *skb)
{
return f1(skb) + f2(2, skb) + f3(3, skb);
}
diff --git a/tools/testing/selftests/bpf/progs/test_global_func7.c b/tools/testing/selftests/bpf/progs/test_global_func7.c
index 6cb8e2f5254c..f182febfde3c 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func7.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func7.c
@@ -3,6 +3,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
__attribute__ ((noinline))
void foo(struct __sk_buff *skb)
@@ -11,7 +12,8 @@ void foo(struct __sk_buff *skb)
}
SEC("tc")
-int test_cls(struct __sk_buff *skb)
+__failure __msg("foo() doesn't return scalar")
+int global_func7(struct __sk_buff *skb)
{
foo(skb);
return 0;
diff --git a/tools/testing/selftests/bpf/progs/test_global_func8.c b/tools/testing/selftests/bpf/progs/test_global_func8.c
index d55a6544b1ab..9b9c57fa2dd3 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func8.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func8.c
@@ -3,6 +3,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
__noinline int foo(struct __sk_buff *skb)
{
@@ -10,7 +11,8 @@ __noinline int foo(struct __sk_buff *skb)
}
SEC("cgroup_skb/ingress")
-int test_cls(struct __sk_buff *skb)
+__success
+int global_func8(struct __sk_buff *skb)
{
if (!foo(skb))
return 0;
diff --git a/tools/testing/selftests/bpf/progs/test_global_func9.c b/tools/testing/selftests/bpf/progs/test_global_func9.c
index bd233ddede98..1f2cb0159b8d 100644
--- a/tools/testing/selftests/bpf/progs/test_global_func9.c
+++ b/tools/testing/selftests/bpf/progs/test_global_func9.c
@@ -2,6 +2,7 @@
#include <stddef.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
struct S {
int x;
@@ -74,7 +75,8 @@ __noinline int quuz(int **p)
}
SEC("cgroup_skb/ingress")
-int test_cls(struct __sk_buff *skb)
+__success
+int global_func9(struct __sk_buff *skb)
{
int result = 0;
--
2.30.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 bpf-next 3/3] selftests/bpf: add global subprog context passing tests
2023-02-16 4:59 [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic Andrii Nakryiko
2023-02-16 4:59 ` [PATCH v2 bpf-next 1/3] bpf: fix global subprog context argument resolution logic Andrii Nakryiko
2023-02-16 4:59 ` [PATCH v2 bpf-next 2/3] selftests/bpf: convert test_global_funcs test to test_loader framework Andrii Nakryiko
@ 2023-02-16 4:59 ` Andrii Nakryiko
2023-02-17 20:24 ` Daniel Borkmann
2023-02-16 17:40 ` [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic Stanislav Fomichev
2023-02-17 20:30 ` patchwork-bot+netdevbpf
4 siblings, 1 reply; 8+ messages in thread
From: Andrii Nakryiko @ 2023-02-16 4:59 UTC (permalink / raw)
To: bpf, ast, daniel; +Cc: andrii, kernel-team
Add tests validating that it's possible to pass context arguments into
global subprogs for various types of programs, including a particularly
tricky KPROBE programs (which cover kprobes, uprobes, USDTs, a vast and
important class of programs).
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
.../bpf/prog_tests/test_global_funcs.c | 2 +
.../bpf/progs/test_global_func_ctx_args.c | 105 ++++++++++++++++++
2 files changed, 107 insertions(+)
create mode 100644 tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c
diff --git a/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c b/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c
index 2ff4d5c7abfc..e0879df38639 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_global_funcs.c
@@ -18,6 +18,7 @@
#include "test_global_func15.skel.h"
#include "test_global_func16.skel.h"
#include "test_global_func17.skel.h"
+#include "test_global_func_ctx_args.skel.h"
void test_test_global_funcs(void)
{
@@ -38,4 +39,5 @@ void test_test_global_funcs(void)
RUN_TESTS(test_global_func15);
RUN_TESTS(test_global_func16);
RUN_TESTS(test_global_func17);
+ RUN_TESTS(test_global_func_ctx_args);
}
diff --git a/tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c b/tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c
new file mode 100644
index 000000000000..754ef56cba21
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_core_read.h>
+#include "bpf_misc.h"
+
+char _license[] SEC("license") = "GPL";
+
+static long stack[256];
+
+/*
+ * KPROBE contexts
+ */
+
+__weak int kprobe_typedef_ctx_subprog(bpf_user_pt_regs_t *ctx)
+{
+ return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
+}
+
+SEC("?kprobe")
+__success
+int kprobe_typedef_ctx(void *ctx)
+{
+ return kprobe_typedef_ctx_subprog(ctx);
+}
+
+#define pt_regs_struct_t typeof(*(__PT_REGS_CAST((struct pt_regs *)NULL)))
+
+__weak int kprobe_struct_ctx_subprog(pt_regs_struct_t *ctx)
+{
+ return bpf_get_stack((void *)ctx, &stack, sizeof(stack), 0);
+}
+
+SEC("?kprobe")
+__success
+int kprobe_resolved_ctx(void *ctx)
+{
+ return kprobe_struct_ctx_subprog(ctx);
+}
+
+/* this is current hack to make this work on old kernels */
+struct bpf_user_pt_regs_t {};
+
+__weak int kprobe_workaround_ctx_subprog(struct bpf_user_pt_regs_t *ctx)
+{
+ return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
+}
+
+SEC("?kprobe")
+__success
+int kprobe_workaround_ctx(void *ctx)
+{
+ return kprobe_workaround_ctx_subprog(ctx);
+}
+
+/*
+ * RAW_TRACEPOINT contexts
+ */
+
+__weak int raw_tp_ctx_subprog(struct bpf_raw_tracepoint_args *ctx)
+{
+ return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
+}
+
+SEC("?raw_tp")
+__success
+int raw_tp_ctx(void *ctx)
+{
+ return raw_tp_ctx_subprog(ctx);
+}
+
+/*
+ * RAW_TRACEPOINT_WRITABLE contexts
+ */
+
+__weak int raw_tp_writable_ctx_subprog(struct bpf_raw_tracepoint_args *ctx)
+{
+ return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
+}
+
+SEC("?raw_tp")
+__success
+int raw_tp_writable_ctx(void *ctx)
+{
+ return raw_tp_writable_ctx_subprog(ctx);
+}
+
+/*
+ * PERF_EVENT contexts
+ */
+
+__weak int perf_event_ctx_subprog(struct bpf_perf_event_data *ctx)
+{
+ return bpf_get_stack(ctx, &stack, sizeof(stack), 0);
+}
+
+SEC("?perf_event")
+__success
+int perf_event_ctx(void *ctx)
+{
+ return perf_event_ctx_subprog(ctx);
+}
+
--
2.30.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic
2023-02-16 4:59 [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic Andrii Nakryiko
` (2 preceding siblings ...)
2023-02-16 4:59 ` [PATCH v2 bpf-next 3/3] selftests/bpf: add global subprog context passing tests Andrii Nakryiko
@ 2023-02-16 17:40 ` Stanislav Fomichev
2023-02-16 19:53 ` Andrii Nakryiko
2023-02-17 20:30 ` patchwork-bot+netdevbpf
4 siblings, 1 reply; 8+ messages in thread
From: Stanislav Fomichev @ 2023-02-16 17:40 UTC (permalink / raw)
To: Andrii Nakryiko; +Cc: bpf, ast, daniel, kernel-team
On 02/15, Andrii Nakryiko wrote:
> Fix kernel bug in determining whether global subprog's argument is
> PTR_TO_CTX,
> which is done based on type names. Currently KPROBE programs are broken.
> Add few tests validating that KPROBE context can be passed to global
> subprog.
> For that also refactor test_global_funcs test to use test_loader
> framework.
> v1->v2:
> - fix compilation warning on arm64 and s390x by force-casting ctx to
> `void *`, to discard const from `const struct user_pt_regs *`, when
> passing it to bpf_get_stack().
Such a shame there isn't something like unconstify(typeof(xxx)) :-(
But thank you for catching this. Need to build a habit of looking at
the buildbot output.
Reposting for patchwork:
Acked-by: Stanislav Fomichev <sdf@google.com>
> Andrii Nakryiko (3):
> bpf: fix global subprog context argument resolution logic
> selftests/bpf: convert test_global_funcs test to test_loader framework
> selftests/bpf: add global subprog context passing tests
> kernel/bpf/btf.c | 13 +-
> .../bpf/prog_tests/test_global_funcs.c | 133 +++++-------------
> .../selftests/bpf/progs/test_global_func1.c | 6 +-
> .../selftests/bpf/progs/test_global_func10.c | 4 +-
> .../selftests/bpf/progs/test_global_func11.c | 4 +-
> .../selftests/bpf/progs/test_global_func12.c | 4 +-
> .../selftests/bpf/progs/test_global_func13.c | 4 +-
> .../selftests/bpf/progs/test_global_func14.c | 4 +-
> .../selftests/bpf/progs/test_global_func15.c | 4 +-
> .../selftests/bpf/progs/test_global_func16.c | 4 +-
> .../selftests/bpf/progs/test_global_func17.c | 4 +-
> .../selftests/bpf/progs/test_global_func2.c | 43 +++++-
> .../selftests/bpf/progs/test_global_func3.c | 10 +-
> .../selftests/bpf/progs/test_global_func4.c | 55 +++++++-
> .../selftests/bpf/progs/test_global_func5.c | 4 +-
> .../selftests/bpf/progs/test_global_func6.c | 4 +-
> .../selftests/bpf/progs/test_global_func7.c | 4 +-
> .../selftests/bpf/progs/test_global_func8.c | 4 +-
> .../selftests/bpf/progs/test_global_func9.c | 4 +-
> .../bpf/progs/test_global_func_ctx_args.c | 105 ++++++++++++++
> 20 files changed, 292 insertions(+), 125 deletions(-)
> create mode 100644
> tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c
> --
> 2.30.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic
2023-02-16 17:40 ` [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic Stanislav Fomichev
@ 2023-02-16 19:53 ` Andrii Nakryiko
0 siblings, 0 replies; 8+ messages in thread
From: Andrii Nakryiko @ 2023-02-16 19:53 UTC (permalink / raw)
To: Stanislav Fomichev; +Cc: Andrii Nakryiko, bpf, ast, daniel, kernel-team
On Thu, Feb 16, 2023 at 9:40 AM Stanislav Fomichev <sdf@google.com> wrote:
>
> On 02/15, Andrii Nakryiko wrote:
> > Fix kernel bug in determining whether global subprog's argument is
> > PTR_TO_CTX,
> > which is done based on type names. Currently KPROBE programs are broken.
>
> > Add few tests validating that KPROBE context can be passed to global
> > subprog.
> > For that also refactor test_global_funcs test to use test_loader
> > framework.
>
> > v1->v2:
> > - fix compilation warning on arm64 and s390x by force-casting ctx to
> > `void *`, to discard const from `const struct user_pt_regs *`, when
> > passing it to bpf_get_stack().
>
> Such a shame there isn't something like unconstify(typeof(xxx)) :-(
> But thank you for catching this. Need to build a habit of looking at
> the buildbot output.
Yep. And yep, me too :)
>
> Reposting for patchwork:
>
> Acked-by: Stanislav Fomichev <sdf@google.com>
Oh, sorry, forgot to carry over your ack from v1.
>
> > Andrii Nakryiko (3):
> > bpf: fix global subprog context argument resolution logic
> > selftests/bpf: convert test_global_funcs test to test_loader framework
> > selftests/bpf: add global subprog context passing tests
>
> > kernel/bpf/btf.c | 13 +-
> > .../bpf/prog_tests/test_global_funcs.c | 133 +++++-------------
> > .../selftests/bpf/progs/test_global_func1.c | 6 +-
> > .../selftests/bpf/progs/test_global_func10.c | 4 +-
> > .../selftests/bpf/progs/test_global_func11.c | 4 +-
> > .../selftests/bpf/progs/test_global_func12.c | 4 +-
> > .../selftests/bpf/progs/test_global_func13.c | 4 +-
> > .../selftests/bpf/progs/test_global_func14.c | 4 +-
> > .../selftests/bpf/progs/test_global_func15.c | 4 +-
> > .../selftests/bpf/progs/test_global_func16.c | 4 +-
> > .../selftests/bpf/progs/test_global_func17.c | 4 +-
> > .../selftests/bpf/progs/test_global_func2.c | 43 +++++-
> > .../selftests/bpf/progs/test_global_func3.c | 10 +-
> > .../selftests/bpf/progs/test_global_func4.c | 55 +++++++-
> > .../selftests/bpf/progs/test_global_func5.c | 4 +-
> > .../selftests/bpf/progs/test_global_func6.c | 4 +-
> > .../selftests/bpf/progs/test_global_func7.c | 4 +-
> > .../selftests/bpf/progs/test_global_func8.c | 4 +-
> > .../selftests/bpf/progs/test_global_func9.c | 4 +-
> > .../bpf/progs/test_global_func_ctx_args.c | 105 ++++++++++++++
> > 20 files changed, 292 insertions(+), 125 deletions(-)
> > create mode 100644
> > tools/testing/selftests/bpf/progs/test_global_func_ctx_args.c
>
> > --
> > 2.30.2
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 bpf-next 3/3] selftests/bpf: add global subprog context passing tests
2023-02-16 4:59 ` [PATCH v2 bpf-next 3/3] selftests/bpf: add global subprog context passing tests Andrii Nakryiko
@ 2023-02-17 20:24 ` Daniel Borkmann
0 siblings, 0 replies; 8+ messages in thread
From: Daniel Borkmann @ 2023-02-17 20:24 UTC (permalink / raw)
To: Andrii Nakryiko, bpf, ast; +Cc: kernel-team
On 2/16/23 5:59 AM, Andrii Nakryiko wrote:
[...]
> +SEC("?perf_event")
> +__success
> +int perf_event_ctx(void *ctx)
> +{
> + return perf_event_ctx_subprog(ctx);
> +}
> +
>
(Fixed up the eof newline while applying.)
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic
2023-02-16 4:59 [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic Andrii Nakryiko
` (3 preceding siblings ...)
2023-02-16 17:40 ` [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic Stanislav Fomichev
@ 2023-02-17 20:30 ` patchwork-bot+netdevbpf
4 siblings, 0 replies; 8+ messages in thread
From: patchwork-bot+netdevbpf @ 2023-02-17 20:30 UTC (permalink / raw)
To: Andrii Nakryiko; +Cc: bpf, ast, daniel, kernel-team
Hello:
This series was applied to bpf/bpf-next.git (master)
by Daniel Borkmann <daniel@iogearbox.net>:
On Wed, 15 Feb 2023 20:59:51 -0800 you wrote:
> Fix kernel bug in determining whether global subprog's argument is PTR_TO_CTX,
> which is done based on type names. Currently KPROBE programs are broken.
>
> Add few tests validating that KPROBE context can be passed to global subprog.
> For that also refactor test_global_funcs test to use test_loader framework.
>
> v1->v2:
> - fix compilation warning on arm64 and s390x by force-casting ctx to
> `void *`, to discard const from `const struct user_pt_regs *`, when
> passing it to bpf_get_stack().
>
> [...]
Here is the summary with links:
- [v2,bpf-next,1/3] bpf: fix global subprog context argument resolution logic
https://git.kernel.org/bpf/bpf-next/c/d384dce281ed
- [v2,bpf-next,2/3] selftests/bpf: convert test_global_funcs test to test_loader framework
https://git.kernel.org/bpf/bpf-next/c/95ebb376176c
- [v2,bpf-next,3/3] selftests/bpf: add global subprog context passing tests
https://git.kernel.org/bpf/bpf-next/c/e2b5cfc978f8
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2023-02-17 20:30 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-02-16 4:59 [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic Andrii Nakryiko
2023-02-16 4:59 ` [PATCH v2 bpf-next 1/3] bpf: fix global subprog context argument resolution logic Andrii Nakryiko
2023-02-16 4:59 ` [PATCH v2 bpf-next 2/3] selftests/bpf: convert test_global_funcs test to test_loader framework Andrii Nakryiko
2023-02-16 4:59 ` [PATCH v2 bpf-next 3/3] selftests/bpf: add global subprog context passing tests Andrii Nakryiko
2023-02-17 20:24 ` Daniel Borkmann
2023-02-16 17:40 ` [PATCH v2 bpf-next 0/3] Fix BPF verifier global subprog context argument logic Stanislav Fomichev
2023-02-16 19:53 ` Andrii Nakryiko
2023-02-17 20:30 ` patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox