selftests/bpf: add tests for sleepable (uk)probes
authorDelyan Kratunov <delyank@fb.com>
Tue, 14 Jun 2022 23:10:44 +0000 (23:10 +0000)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 17 Jun 2022 02:27:30 +0000 (19:27 -0700)
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: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Delyan Kratunov <delyank@fb.com>
Link: https://lore.kernel.org/r/c744e5bb7a5c0703f05444dc41f2522ba3579a48.1655248076.git.delyank@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/prog_tests/attach_probe.c
tools/testing/selftests/bpf/progs/test_attach_probe.c

index 08c0601..0b899d2 100644 (file)
@@ -17,6 +17,14 @@ static void trigger_func2(void)
        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)
 {
        DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
@@ -49,9 +57,17 @@ void test_attach_probe(void)
        if (!ASSERT_GE(ref_ctr_offset, 0, "ref_ctr_offset"))
                return;
 
-       skel = test_attach_probe__open_and_load();
+       skel = test_attach_probe__open();
        if (!ASSERT_OK_PTR(skel, "skel_open"))
                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"))
                goto cleanup;
 
@@ -151,6 +167,30 @@ void test_attach_probe(void)
        if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname2, "attach_uretprobe_byname2"))
                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 */
        usleep(1);
 
@@ -164,6 +204,9 @@ void test_attach_probe(void)
        /* trigger & validate uprobe attached by name */
        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->kprobe2_res, 11, "check_kprobe_auto_res");
        ASSERT_EQ(skel->bss->kretprobe_res, 2, "check_kretprobe_res");
@@ -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->uprobe_byname2_res, 7, "check_uprobe_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:
        test_attach_probe__destroy(skel);
index ce9acf4..f1c88ad 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/bpf.h>
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_tracing.h>
+#include <stdbool.h>
 #include "bpf_misc.h"
 
 int kprobe_res = 0;
@@ -17,6 +18,11 @@ int uprobe_byname_res = 0;
 int uretprobe_byname_res = 0;
 int uprobe_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")
 int handle_kprobe(struct pt_regs *ctx)
@@ -32,6 +38,17 @@ int BPF_KPROBE(handle_kprobe_auto)
        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")
 int handle_kretprobe(struct pt_regs *ctx)
 {
@@ -93,4 +110,47 @@ int handle_uretprobe_byname2(struct pt_regs *ctx)
        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";