Commit cb3f4a4a authored by Delyan Kratunov's avatar Delyan Kratunov Committed by Alexei Starovoitov

selftests/bpf: add tests for sleepable (uk)probes

Add tests that ensure sleepable uprobe programs work correctly.
Add tests that ensure sleepable kprobe programs cannot attach.

Also add tests that attach both sleepable and non-sleepable
uprobe programs to the same location (i.e. same bpf_prog_array).
Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarDelyan Kratunov <delyank@fb.com>
Link: https://lore.kernel.org/r/c744e5bb7a5c0703f05444dc41f2522ba3579a48.1655248076.git.delyank@fb.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent c4cac71f
...@@ -17,6 +17,14 @@ static void trigger_func2(void) ...@@ -17,6 +17,14 @@ static void trigger_func2(void)
asm volatile (""); asm volatile ("");
} }
/* attach point for byname sleepable uprobe */
static void trigger_func3(void)
{
asm volatile ("");
}
static char test_data[] = "test_data";
void test_attach_probe(void) void test_attach_probe(void)
{ {
DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts); DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
...@@ -49,9 +57,17 @@ void test_attach_probe(void) ...@@ -49,9 +57,17 @@ void test_attach_probe(void)
if (!ASSERT_GE(ref_ctr_offset, 0, "ref_ctr_offset")) if (!ASSERT_GE(ref_ctr_offset, 0, "ref_ctr_offset"))
return; return;
skel = test_attach_probe__open_and_load(); skel = test_attach_probe__open();
if (!ASSERT_OK_PTR(skel, "skel_open")) if (!ASSERT_OK_PTR(skel, "skel_open"))
return; return;
/* sleepable kprobe test case needs flags set before loading */
if (!ASSERT_OK(bpf_program__set_flags(skel->progs.handle_kprobe_sleepable,
BPF_F_SLEEPABLE), "kprobe_sleepable_flags"))
goto cleanup;
if (!ASSERT_OK(test_attach_probe__load(skel), "skel_load"))
goto cleanup;
if (!ASSERT_OK_PTR(skel->bss, "check_bss")) if (!ASSERT_OK_PTR(skel->bss, "check_bss"))
goto cleanup; goto cleanup;
...@@ -151,6 +167,30 @@ void test_attach_probe(void) ...@@ -151,6 +167,30 @@ void test_attach_probe(void)
if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname2, "attach_uretprobe_byname2")) if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname2, "attach_uretprobe_byname2"))
goto cleanup; goto cleanup;
/* sleepable kprobes should not attach successfully */
skel->links.handle_kprobe_sleepable = bpf_program__attach(skel->progs.handle_kprobe_sleepable);
if (!ASSERT_ERR_PTR(skel->links.handle_kprobe_sleepable, "attach_kprobe_sleepable"))
goto cleanup;
/* test sleepable uprobe and uretprobe variants */
skel->links.handle_uprobe_byname3_sleepable = bpf_program__attach(skel->progs.handle_uprobe_byname3_sleepable);
if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname3_sleepable, "attach_uprobe_byname3_sleepable"))
goto cleanup;
skel->links.handle_uprobe_byname3 = bpf_program__attach(skel->progs.handle_uprobe_byname3);
if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname3, "attach_uprobe_byname3"))
goto cleanup;
skel->links.handle_uretprobe_byname3_sleepable = bpf_program__attach(skel->progs.handle_uretprobe_byname3_sleepable);
if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname3_sleepable, "attach_uretprobe_byname3_sleepable"))
goto cleanup;
skel->links.handle_uretprobe_byname3 = bpf_program__attach(skel->progs.handle_uretprobe_byname3);
if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname3, "attach_uretprobe_byname3"))
goto cleanup;
skel->bss->user_ptr = test_data;
/* trigger & validate kprobe && kretprobe */ /* trigger & validate kprobe && kretprobe */
usleep(1); usleep(1);
...@@ -164,6 +204,9 @@ void test_attach_probe(void) ...@@ -164,6 +204,9 @@ void test_attach_probe(void)
/* trigger & validate uprobe attached by name */ /* trigger & validate uprobe attached by name */
trigger_func2(); trigger_func2();
/* trigger & validate sleepable uprobe attached by name */
trigger_func3();
ASSERT_EQ(skel->bss->kprobe_res, 1, "check_kprobe_res"); ASSERT_EQ(skel->bss->kprobe_res, 1, "check_kprobe_res");
ASSERT_EQ(skel->bss->kprobe2_res, 11, "check_kprobe_auto_res"); ASSERT_EQ(skel->bss->kprobe2_res, 11, "check_kprobe_auto_res");
ASSERT_EQ(skel->bss->kretprobe_res, 2, "check_kretprobe_res"); ASSERT_EQ(skel->bss->kretprobe_res, 2, "check_kretprobe_res");
...@@ -174,6 +217,10 @@ void test_attach_probe(void) ...@@ -174,6 +217,10 @@ void test_attach_probe(void)
ASSERT_EQ(skel->bss->uretprobe_byname_res, 6, "check_uretprobe_byname_res"); ASSERT_EQ(skel->bss->uretprobe_byname_res, 6, "check_uretprobe_byname_res");
ASSERT_EQ(skel->bss->uprobe_byname2_res, 7, "check_uprobe_byname2_res"); ASSERT_EQ(skel->bss->uprobe_byname2_res, 7, "check_uprobe_byname2_res");
ASSERT_EQ(skel->bss->uretprobe_byname2_res, 8, "check_uretprobe_byname2_res"); ASSERT_EQ(skel->bss->uretprobe_byname2_res, 8, "check_uretprobe_byname2_res");
ASSERT_EQ(skel->bss->uprobe_byname3_sleepable_res, 9, "check_uprobe_byname3_sleepable_res");
ASSERT_EQ(skel->bss->uprobe_byname3_res, 10, "check_uprobe_byname3_res");
ASSERT_EQ(skel->bss->uretprobe_byname3_sleepable_res, 11, "check_uretprobe_byname3_sleepable_res");
ASSERT_EQ(skel->bss->uretprobe_byname3_res, 12, "check_uretprobe_byname3_res");
cleanup: cleanup:
test_attach_probe__destroy(skel); test_attach_probe__destroy(skel);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/bpf.h> #include <linux/bpf.h>
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h> #include <bpf/bpf_tracing.h>
#include <stdbool.h>
#include "bpf_misc.h" #include "bpf_misc.h"
int kprobe_res = 0; int kprobe_res = 0;
...@@ -17,6 +18,11 @@ int uprobe_byname_res = 0; ...@@ -17,6 +18,11 @@ int uprobe_byname_res = 0;
int uretprobe_byname_res = 0; int uretprobe_byname_res = 0;
int uprobe_byname2_res = 0; int uprobe_byname2_res = 0;
int uretprobe_byname2_res = 0; int uretprobe_byname2_res = 0;
int uprobe_byname3_sleepable_res = 0;
int uprobe_byname3_res = 0;
int uretprobe_byname3_sleepable_res = 0;
int uretprobe_byname3_res = 0;
void *user_ptr = 0;
SEC("kprobe") SEC("kprobe")
int handle_kprobe(struct pt_regs *ctx) int handle_kprobe(struct pt_regs *ctx)
...@@ -32,6 +38,17 @@ int BPF_KPROBE(handle_kprobe_auto) ...@@ -32,6 +38,17 @@ int BPF_KPROBE(handle_kprobe_auto)
return 0; return 0;
} }
/**
* This program will be manually made sleepable on the userspace side
* and should thus be unattachable.
*/
SEC("kprobe/" SYS_PREFIX "sys_nanosleep")
int handle_kprobe_sleepable(struct pt_regs *ctx)
{
kprobe_res = 2;
return 0;
}
SEC("kretprobe") SEC("kretprobe")
int handle_kretprobe(struct pt_regs *ctx) int handle_kretprobe(struct pt_regs *ctx)
{ {
...@@ -93,4 +110,47 @@ int handle_uretprobe_byname2(struct pt_regs *ctx) ...@@ -93,4 +110,47 @@ int handle_uretprobe_byname2(struct pt_regs *ctx)
return 0; return 0;
} }
static __always_inline bool verify_sleepable_user_copy(void)
{
char data[9];
bpf_copy_from_user(data, sizeof(data), user_ptr);
return bpf_strncmp(data, sizeof(data), "test_data") == 0;
}
SEC("uprobe.s//proc/self/exe:trigger_func3")
int handle_uprobe_byname3_sleepable(struct pt_regs *ctx)
{
if (verify_sleepable_user_copy())
uprobe_byname3_sleepable_res = 9;
return 0;
}
/**
* same target as the uprobe.s above to force sleepable and non-sleepable
* programs in the same bpf_prog_array
*/
SEC("uprobe//proc/self/exe:trigger_func3")
int handle_uprobe_byname3(struct pt_regs *ctx)
{
uprobe_byname3_res = 10;
return 0;
}
SEC("uretprobe.s//proc/self/exe:trigger_func3")
int handle_uretprobe_byname3_sleepable(struct pt_regs *ctx)
{
if (verify_sleepable_user_copy())
uretprobe_byname3_sleepable_res = 11;
return 0;
}
SEC("uretprobe//proc/self/exe:trigger_func3")
int handle_uretprobe_byname3(struct pt_regs *ctx)
{
uretprobe_byname3_res = 12;
return 0;
}
char _license[] SEC("license") = "GPL"; char _license[] SEC("license") = "GPL";
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment